diff --git a/.github/ISSUE_TEMPLATE/new-release.md b/.github/ISSUE_TEMPLATE/new-release.md index fe851832b4a..6e4c4296c12 100644 --- a/.github/ISSUE_TEMPLATE/new-release.md +++ b/.github/ISSUE_TEMPLATE/new-release.md @@ -75,6 +75,7 @@ Do the following steps to keep track of spartacussampledata releases: - [ ] `npm run release:core:with-changelog` - [ ] `npm run release:storefront:with-changelog` - [ ] `npm run release:user:with-changelog` (needed since `3.2.0-rc.0`) + - [ ] `npm run release:tracking:with-changelog` (needed since `3.2.0-next.0`) - [ ] `npm run release:cds:with-changelog` - [ ] `npm run release:assets:with-changelog` - [ ] `npm run release:styles:with-changelog` @@ -84,7 +85,6 @@ Do the following steps to keep track of spartacussampledata releases: - [ ] `npm run release:setup:with-changelog` (needed since `3.0.0-next.1`) - [ ] `npm run release:organization:with-changelog` (needed since `3.0.0-next.1`) - [ ] `npm run release:storefinder:with-changelog` (needed since `3.0.0-rc.0`) - - [ ] `npm run release:tracking:with-changelog` (needed since `3.2.0-next.0`) - [ ] `npm run release:product:with-changelog` (needed since `3.2.0-next.1`) - [ ] `npm run release:smartedit:with-changelog` (needed since `3.2.0-next.0`) - [ ] `npm run release:qualtrics:with-changelog` (needed since `3.1.0-next.0`) diff --git a/docs/migration/4_0.md b/docs/migration/4_0.md index e4b8bcd9328..e7f48019aa7 100644 --- a/docs/migration/4_0.md +++ b/docs/migration/4_0.md @@ -2,6 +2,102 @@ ## Breaking Changes Introduced in 4.0 +### ASM changes + +- `AsmModule` was removed from storefrontlib, and renamed AsmComponentsModule. Use @spartacus/asm/components instead. +- `AsmModule` was removed from core, and renamed AsmCoreModule. Use @spartacus/asm/core. instead. +- `AsmConfig` was removed from core. Use @spartacus/asm/core. +- `AsmAdapter` was removed. Use @spartacus/asm/core instead. +- `AsmConnector` was removed. Use @spartacus/asm/core instead. +- `CUSTOMER_SEARCH_PAGE_NORMALIZER` was removed. Use @spartacus/asm/core instead. +- `AsmService` was removed. Use @spartacus/asm/core instead. +- `CsAgentAuthService` was removed. Use @spartacus/asm/root instead. +- `CustomerSearchPage` was removed. Use @spartacus/asm/core instead. +- `CustomerSearchOptions` was removed. Use @spartacus/asm/core instead. +- `AsmUi` was removed. Use @spartacus/asm/core instead. +- `AsmAuthHttpHeaderService` was removed. Use @spartacus/asm/root instead. +- `TOKEN_TARGET` was removed. Use @spartacus/asm/root instead. +- `AsmAuthService` was removed. Use @spartacus/asm/root instead. +- `AsmAuthStorageService` was removed. Use @spartacus/asm/root instead. +- `SYNCED_ASM_STATE` was removed. Use @spartacus/asm/core instead. +- `AsmStatePersistenceService` was removed. Use @spartacus/asm/core instead. +- `ASM_UI_UPDATE` was removed. Use @spartacus/asm/core instead. +- `AsmUiUpdate` was removed. Use @spartacus/asm/core instead. +- `AsmUiAction` was removed. Use @spartacus/asm/core instead. +- `CUSTOMER_SEARCH` was removed. Use @spartacus/asm/core instead. +- `CUSTOMER_SEARCH_FAIL` was removed. Use @spartacus/asm/core instead. +- `CUSTOMER_SEARCH_SUCCESS` was removed. Use @spartacus/asm/core instead. +- `CUSTOMER_SEARCH_RESET` was removed. Use @spartacus/asm/core instead. +- `CustomerSearch` was removed. Use @spartacus/asm/core instead. +- `CustomerSearchFail` was removed. Use @spartacus/asm/core instead. +- `CustomerSearchSuccess` was removed. Use @spartacus/asm/core instead. +- `CustomerSearchReset` was removed. Use @spartacus/asm/core instead. +- `CustomerAction` was removed. Use @spartacus/asm/core instead. +- `LOGOUT_CUSTOMER_SUPPORT_AGENT` was removed. Use @spartacus/asm/core instead. +- `LogoutCustomerSupportAgent` was removed. Use @spartacus/asm/core instead. +- `ASM_FEATURE` was removed. Use @spartacus/asm/core instead. +- `CUSTOMER_SEARCH_DATA` was removed. Use @spartacus/asm/core instead. +- `StateWithAsm` was removed. Use @spartacus/asm/core instead. +- `AsmState` was removed. Use @spartacus/asm/core instead. +- `getAsmUi` was removed. Use @spartacus/asm/core instead. +- `getCustomerSearchResultsLoaderState` was removed. Use @spartacus/asm/core instead. +- `getCustomerSearchResults` was removed. Use @spartacus/asm/core instead. +- `getCustomerSearchResultsLoading` was removed. Use @spartacus/asm/core instead. +- `getAsmState` was removed. Use @spartacus/asm/core instead. + +### LaunchDialogService + +#### SavedCartFormLaunchDialogService +- Service has been removed. `openDialog` method is part of LaunchDialogService now. + +#### AddToSavedCartComponent +- Removed `SavedCartFormLaunchDialogService` from constructor. +- Added `LaunchDialogService` to constructor. + +#### SavedCartDetailsActionComponent +- Removed `SavedCartFormLaunchDialogService` from constructor. +- Added `LaunchDialogService` to constructor. + +#### SavedCartDetailsOverviewComponent +- Removed `SavedCartFormLaunchDialogService` from constructor. +- Added `LaunchDialogService` to constructor. + +#### AnonymousConsentLaunchDialogService +- Service has been removed. `openDialog` method is part of LaunchDialogService now. + +#### AnonymousConsentManagementBannerComponent +- Removed `AnonymousConsentLaunchDialogService` from constructor. +- Added `LaunchDialogService` to constructor. + +#### AnonymousConsentOpenDialogComponent +- Removed `AnonymousConsentLaunchDialogService` from constructor. +- Added `LaunchDialogService` to constructor. + +#### ReplenishmentOrderCancellationLaunchDialogService +- Service has been removed. `openDialog` method is part of LaunchDialogService now. + +#### ReplenishmentOrderCancellationComponent +- Removed `ReplenishmentOrderCancellationLaunchDialogService` from constructor. +- Added `LaunchDialogService` to constructor. + +#### ReplenishmentOrderHistoryComponent +- Removed `ReplenishmentOrderCancellationLaunchDialogService` from constructor. +- Added `LaunchDialogService` to constructor. + +### Personalization + +- `PersonalizationModule` was removed. Use `@spartacus/tracking/personalization` instead. +- `PersonalizationConfig` was moved to `@spartacus/tracking/personalization/root`. +- `PersonalizationContextService` was moved to `@spartacus/tracking/personalization/core`. +- `PersonalizationAction` was moved to `@spartacus/tracking/personalization/core`. +- `PersonalizationContext` was moved to `@spartacus/tracking/personalization/core`. + +### WindowRef + +- `platformId` is now required constructor dependency. + +### Product configurator + `ConfiguratorCartEntryInfoComponent` now also requires `CommonConfiguratorUtilsService`. `ConfiguratorAttributeCheckboxListComponent` now also requires `ConfiguratorAttributeQuantityService`. `ConfiguratorAttributeDropDownComponent` now also requires `ConfiguratorAttributeQuantityService`. @@ -81,3 +177,17 @@ What was removed: - core of the mechanism (reducer) - configuration (`storageSync` from `StateConfig`) - default config and default keys (`defaultStateConfig`, `DEFAULT_LOCAL_STORAGE_KEY` and `DEFAULT_SESSION_STORAGE_KEY`) + +### LanguageService + +- `LanguageService` no longer uses `WindowRef`. The language initialization from the state was moved to `LanguageInitializer`. +- `LanguageService` now validate the value passed to the method `setActive()` against the iso codes listed in the Spartacus `context` config, before setting the actual value in the ngrx store. +- The initialization of the site context is scheduled a bit earlier than in before (now it's run in an observable stream instead of a Promise's callback). It's a very slight change, but might have side-effects in some custom implementations. +- The active language is now persisted in the Local Storage instead of the Session Storage + +### CurrencyService + +- `CurrencyService` no longer uses `WindowRef`. The currency initialization from the state was moved to `CurrencyInitializer`. +- `CurrencyService` now validate the value passed to the method `setActive()` against the iso codes listed in the Spartacus `context` config, before setting the actual value in the ngrx store. +- The initialization of the site context is scheduled a bit earlier than in before (now it's run in an observable stream instead of a Promise's callback). It's a very slight change, but might have side-effects in some custom implementations. +- The active currency is now persisted in the LocalStorage instead of the Session Storage. diff --git a/feature-libs/asm/occ/model/index.ts b/feature-libs/asm/occ/model/index.ts new file mode 100644 index 00000000000..7111390f5f1 --- /dev/null +++ b/feature-libs/asm/occ/model/index.ts @@ -0,0 +1 @@ +export * from './occ-asm-endpoints.model'; diff --git a/feature-libs/asm/occ/model/occ-asm-endpoints.model.ts b/feature-libs/asm/occ/model/occ-asm-endpoints.model.ts new file mode 100644 index 00000000000..c050b8d3235 --- /dev/null +++ b/feature-libs/asm/occ/model/occ-asm-endpoints.model.ts @@ -0,0 +1,12 @@ +import { OccEndpoint } from '@spartacus/core'; + +declare module '@spartacus/core' { + interface OccEndpoints { + /** + * Endpoint for asm customer search + * + * @member {string} + */ + asmCustomerSearch?: string | OccEndpoint; + } +} diff --git a/feature-libs/asm/occ/public_api.ts b/feature-libs/asm/occ/public_api.ts index 70a5beeb57c..4fc666e1314 100644 --- a/feature-libs/asm/occ/public_api.ts +++ b/feature-libs/asm/occ/public_api.ts @@ -1,2 +1,3 @@ export * from './adapters/index'; export * from './asm-occ.module'; +export * from './model/index'; diff --git a/feature-libs/asm/schematics/add-asm/index_spec.ts b/feature-libs/asm/schematics/add-asm/index_spec.ts index 8f3a85f5b36..d4bcce9b622 100644 --- a/feature-libs/asm/schematics/add-asm/index_spec.ts +++ b/feature-libs/asm/schematics/add-asm/index_spec.ts @@ -44,7 +44,6 @@ describe('Spartacus Asm schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.spec.ts b/feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.spec.ts index e3b65812b23..bc214b6d502 100644 --- a/feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.spec.ts +++ b/feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.spec.ts @@ -11,7 +11,6 @@ import { import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; import { UrlTestingModule } from 'projects/core/src/routing/configurable-routes/url-translation/testing/url-testing.module'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { SavedCartFormLaunchDialogService } from '../saved-cart-form-dialog/saved-cart-form-launch-dialog.service'; import { AddToSavedCartComponent } from './add-to-saved-cart.component'; const mockCart: Cart = { @@ -39,10 +38,6 @@ class MockRoutingService implements Partial { go(): void {} } -class MockSavedCartFormLaunchDialogService { - openDialog(_openElement?: ElementRef, _vcr?: ViewContainerRef, _data?: any) {} -} - class MockLaunchDialogService implements Partial { openDialog( _caller: LAUNCH_CALLER, @@ -67,11 +62,6 @@ describe('AddToSavedCartComponent', () => { { provide: ActiveCartService, useClass: MockActiveCartService }, { provide: AuthService, useClass: MockAuthService }, { provide: RoutingService, useClass: MockRoutingService }, - // TODO(#12167): remove unused class and provider - { - provide: SavedCartFormLaunchDialogService, - useClass: MockSavedCartFormLaunchDialogService, - }, { provide: LaunchDialogService, useClass: MockLaunchDialogService }, ], }).compileComponents(); diff --git a/feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.ts b/feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.ts index 77559d4f4d2..7584095cf7c 100644 --- a/feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.ts +++ b/feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.ts @@ -16,7 +16,6 @@ import { import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; import { combineLatest, Observable, Subscription } from 'rxjs'; import { map, take, tap } from 'rxjs/operators'; -import { SavedCartFormLaunchDialogService } from '../saved-cart-form-dialog/saved-cart-form-launch-dialog.service'; @Component({ selector: 'cx-add-to-saved-cart', @@ -31,43 +30,12 @@ export class AddToSavedCartComponent implements OnInit, OnDestroy { cart$: Observable; - // TODO(#12167): make launchDialogService a required dependency instead of savedCartFormLaunchDialogService and remove deprecated constructors - /** - * Default constructor will be: - * - * @param {ActiveCartService} activeCartService - * @param {AuthService} authService - * @param {RoutingService} routingService - * @param {ViewContainerRef} vcr - * @param {LaunchDialogService} launchDialogService - */ - constructor( - activeCartService: ActiveCartService, - authService: AuthService, - routingService: RoutingService, - savedCartFormLaunchDialogService: SavedCartFormLaunchDialogService, - vcr: ViewContainerRef, - // eslint-disable-next-line @typescript-eslint/unified-signatures - launchDialogService: LaunchDialogService - ); - - /** - * @deprecated since 3.3 - */ - constructor( - activeCartService: ActiveCartService, - authService: AuthService, - routingService: RoutingService, - savedCartFormLaunchDialogService: SavedCartFormLaunchDialogService, - vcr: ViewContainerRef - ); constructor( protected activeCartService: ActiveCartService, protected authService: AuthService, protected routingService: RoutingService, - protected savedCartFormLaunchDialogService: SavedCartFormLaunchDialogService, protected vcr: ViewContainerRef, - protected launchDialogService?: LaunchDialogService + protected launchDialogService: LaunchDialogService ) {} ngOnInit(): void { @@ -89,28 +57,15 @@ export class AddToSavedCartComponent implements OnInit, OnDestroy { } openDialog(cart: Cart) { - // TODO(#12167): use launchDialogService only - if (this.launchDialogService) { - const dialog = this.launchDialogService.openDialog( - LAUNCH_CALLER.SAVED_CART, - this.element, - this.vcr, - { cart, layoutOption: 'save' } - ); - - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } - } else { - const dialog = this.savedCartFormLaunchDialogService.openDialog( - this.element, - this.vcr, - { cart, layoutOption: 'save' } - ); + const dialog = this.launchDialogService.openDialog( + LAUNCH_CALLER.SAVED_CART, + this.element, + this.vcr, + { cart, layoutOption: 'save' } + ); - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } + if (dialog) { + this.subscription.add(dialog.pipe(take(1)).subscribe()); } } diff --git a/feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.spec.ts b/feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.spec.ts index 1a3f91df769..64a176b40d0 100644 --- a/feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.spec.ts +++ b/feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.spec.ts @@ -11,7 +11,6 @@ import { } from '@spartacus/core'; import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; import { Observable, of } from 'rxjs'; -import { SavedCartFormLaunchDialogService } from '../../saved-cart-form-dialog/saved-cart-form-launch-dialog.service'; import { SavedCartDetailsService } from '../saved-cart-details.service'; import { SavedCartDetailsActionComponent } from './saved-cart-details-action.component'; @@ -50,17 +49,6 @@ class MockGlobalMessageService implements Partial { ): void {} } -class MockSavedCartFormLaunchDialogService - implements Partial { - openDialog( - _openElement?: ElementRef, - _vcr?: ViewContainerRef, - _data?: any - ): Observable { - return of(); - } -} - class MockClearCheckoutService implements Partial { resetCheckoutProcesses(): void {} } @@ -103,11 +91,6 @@ describe('SavedCartDetailsActionComponent', () => { provide: GlobalMessageService, useClass: MockGlobalMessageService, }, - // TODO(#12167): remove unused class and provider - { - provide: SavedCartFormLaunchDialogService, - useClass: MockSavedCartFormLaunchDialogService, - }, { provide: ClearCheckoutService, useClass: MockClearCheckoutService, diff --git a/feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.ts b/feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.ts index 21a489e4cfb..9457afed206 100644 --- a/feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.ts +++ b/feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.ts @@ -16,7 +16,6 @@ import { import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; import { Observable, Subscription } from 'rxjs'; import { take } from 'rxjs/operators'; -import { SavedCartFormLaunchDialogService } from '../../saved-cart-form-dialog/saved-cart-form-launch-dialog.service'; import { SavedCartDetailsService } from '../saved-cart-details.service'; @Component({ @@ -31,52 +30,14 @@ export class SavedCartDetailsActionComponent implements OnInit, OnDestroy { Cart | undefined > = this.savedCartDetailsService.getCartDetails(); - // TODO(#12167): make launchDialogService a required dependency instead of savedCartFormLaunchDialogService and remove deprecated constructors - /** - * Default constructor will be - * - * @param {SavedCartDetailsService} savedCartDetailsService - * @param {SavedCartFacade} savedCartService - * @param {RoutingService} routingService - * @param {GlobalMessageService} globalMessageService - * @param {ViewContainerRef} vcr - * @param {ClearCheckoutService} clearCheckoutService - * @param {LaunchDialogService} launchDialogService - */ - constructor( - savedCartDetailsService: SavedCartDetailsService, - savedCartService: SavedCartFacade, - routingService: RoutingService, - globalMessageService: GlobalMessageService, - savedCartFormLaunchDialogService: SavedCartFormLaunchDialogService, - vcr: ViewContainerRef, - clearCheckoutService: ClearCheckoutService, - // eslint-disable-next-line @typescript-eslint/unified-signatures - launchDialogService: LaunchDialogService - ); - - /** - * @deprecated since 3.3 - */ - constructor( - savedCartDetailsService: SavedCartDetailsService, - savedCartService: SavedCartFacade, - routingService: RoutingService, - globalMessageService: GlobalMessageService, - savedCartFormLaunchDialogService: SavedCartFormLaunchDialogService, - vcr: ViewContainerRef, - clearCheckoutService: ClearCheckoutService - ); - constructor( protected savedCartDetailsService: SavedCartDetailsService, protected savedCartService: SavedCartFacade, protected routingService: RoutingService, protected globalMessageService: GlobalMessageService, - protected savedCartFormLaunchDialogService: SavedCartFormLaunchDialogService, protected vcr: ViewContainerRef, protected clearCheckoutService: ClearCheckoutService, - protected launchDialogService?: LaunchDialogService + protected launchDialogService: LaunchDialogService ) {} ngOnInit(): void { @@ -101,28 +62,15 @@ export class SavedCartDetailsActionComponent implements OnInit, OnDestroy { } openDialog(cart: Cart): void { - // TODO(#12167): use launchDialogService only - if (this.launchDialogService) { - const dialog = this.launchDialogService.openDialog( - LAUNCH_CALLER.SAVED_CART, - this.element, - this.vcr, - { cart, layoutOption: 'delete' } - ); - - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } - } else { - const dialog = this.savedCartFormLaunchDialogService.openDialog( - this.element, - this.vcr, - { cart, layoutOption: 'delete' } - ); + const dialog = this.launchDialogService.openDialog( + LAUNCH_CALLER.SAVED_CART, + this.element, + this.vcr, + { cart, layoutOption: 'delete' } + ); - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } + if (dialog) { + this.subscription.add(dialog.pipe(take(1)).subscribe()); } } diff --git a/feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.spec.ts b/feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.spec.ts index 53ebaec7843..269b4cf9eef 100644 --- a/feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.spec.ts +++ b/feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.spec.ts @@ -3,7 +3,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { Cart, I18nTestingModule, TranslationService } from '@spartacus/core'; import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; import { Observable, of } from 'rxjs'; -import { SavedCartFormLaunchDialogService } from '../../saved-cart-form-dialog/saved-cart-form-launch-dialog.service'; import { SavedCartDetailsService } from '../saved-cart-details.service'; import { SavedCartDetailsOverviewComponent } from './saved-cart-details-overview.component'; @@ -25,16 +24,6 @@ class MockSavedCartDetailsService implements Partial { return of(mockSavedCart); } } -class MockSavedCartFormLaunchDialogService - implements Partial { - openDialog( - _openElement?: ElementRef, - _vcr?: ViewContainerRef, - _data?: any - ): Observable { - return of(); - } -} class MockTranslationService { translate(): Observable { @@ -66,11 +55,6 @@ describe('SavedCartDetailsOverviewComponent', () => { provide: SavedCartDetailsService, useClass: MockSavedCartDetailsService, }, - // TODO(#12167): remove unused class and provider - { - provide: SavedCartFormLaunchDialogService, - useClass: MockSavedCartFormLaunchDialogService, - }, { provide: TranslationService, useClass: MockTranslationService }, { provide: LaunchDialogService, useClass: MockLaunchDialogService }, ], diff --git a/feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.ts b/feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.ts index 029327e3b50..c928afed578 100644 --- a/feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.ts +++ b/feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.ts @@ -14,7 +14,6 @@ import { } from '@spartacus/storefront'; import { Observable, Subscription } from 'rxjs'; import { filter, map, take } from 'rxjs/operators'; -import { SavedCartFormLaunchDialogService } from '../../saved-cart-form-dialog/saved-cart-form-launch-dialog.service'; import { SavedCartDetailsService } from '../saved-cart-details.service'; @Component({ @@ -31,39 +30,11 @@ export class SavedCartDetailsOverviewComponent implements OnDestroy { Cart | undefined > = this.savedCartDetailsService.getCartDetails(); - // TODO(#12167): make launchDialogService a required dependency instead of savedCartFormLaunchDialogService and remove deprecated constructors - /** - * Default constructor will be - * - * @param {SavedCartDetailsService} savedCartDetailsService - * @param {TranslationService} translation - * @param {ViewContainerRef} vcr - * @param {LaunchDialogService} launchDialogService - */ - constructor( - savedCartDetailsService: SavedCartDetailsService, - translation: TranslationService, - savedCartFormLaunchDialogService: SavedCartFormLaunchDialogService, - vcr: ViewContainerRef, - // eslint-disable-next-line @typescript-eslint/unified-signatures - launchDialogService: LaunchDialogService - ); - - /** - * @deprecated since 3.3 - */ - constructor( - savedCartDetailsService: SavedCartDetailsService, - translation: TranslationService, - savedCartFormLaunchDialogService: SavedCartFormLaunchDialogService, - vcr: ViewContainerRef - ); constructor( protected savedCartDetailsService: SavedCartDetailsService, protected translation: TranslationService, - protected savedCartFormLaunchDialogService: SavedCartFormLaunchDialogService, protected vcr: ViewContainerRef, - protected launchDialogService?: LaunchDialogService + protected launchDialogService: LaunchDialogService ) {} getCartName(cartName: string): Observable { @@ -141,28 +112,15 @@ export class SavedCartDetailsOverviewComponent implements OnDestroy { } openDialog(cart: Cart): void { - // TODO(#12167): use launchDialogService only - if (this.launchDialogService) { - const dialog = this.launchDialogService.openDialog( - LAUNCH_CALLER.SAVED_CART, - this.element, - this.vcr, - { cart, layoutOption: 'edit' } - ); - - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } - } else { - const dialog = this.savedCartFormLaunchDialogService.openDialog( - this.element, - this.vcr, - { cart, layoutOption: 'edit' } - ); - - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } + const dialog = this.launchDialogService.openDialog( + LAUNCH_CALLER.SAVED_CART, + this.element, + this.vcr, + { cart, layoutOption: 'edit' } + ); + + if (dialog) { + this.subscription.add(dialog.pipe(take(1)).subscribe()); } } diff --git a/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/index.ts b/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/index.ts index 33a5eefa5bd..1e6700801d3 100644 --- a/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/index.ts +++ b/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/index.ts @@ -1,4 +1,3 @@ export * from './default-saved-cart-form-layout.config'; export * from './saved-cart-form-dialog.component'; export * from './saved-cart-form-dialog.module'; -export * from './saved-cart-form-launch-dialog.service'; diff --git a/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/saved-cart-form-launch-dialog.service.spec.ts b/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/saved-cart-form-launch-dialog.service.spec.ts deleted file mode 100644 index 2209422393c..00000000000 --- a/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/saved-cart-form-launch-dialog.service.spec.ts +++ /dev/null @@ -1,89 +0,0 @@ -// TODO(#12167): remove the file -import { Component, ComponentRef, ViewContainerRef } from '@angular/core'; -import { TestBed } from '@angular/core/testing'; -import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; -import { of } from 'rxjs'; -import { SavedCartFormLaunchDialogService } from './saved-cart-form-launch-dialog.service'; - -@Component({ - template: '', -}) -class TestContainerComponent { - constructor(public vcr: ViewContainerRef) {} -} - -class MockLaunchDialogService implements Partial { - launch( - _caller: LAUNCH_CALLER | string, - _vcr?: ViewContainerRef, - _data?: any - ): void {} - clear(_caller: LAUNCH_CALLER | string) {} - get dialogClose() { - return of('close'); - } -} - -describe('SavedCartFormLaunchDialogService', () => { - let service: SavedCartFormLaunchDialogService; - let launchDialogService: LaunchDialogService; - let component: TestContainerComponent; - let componentRef: ComponentRef; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [TestContainerComponent], - providers: [ - { provide: LaunchDialogService, useClass: MockLaunchDialogService }, - ], - }).compileComponents(); - - service = TestBed.inject(SavedCartFormLaunchDialogService); - launchDialogService = TestBed.inject(LaunchDialogService); - component = TestBed.createComponent(TestContainerComponent) - .componentInstance; - componentRef = TestBed.createComponent(TestContainerComponent).componentRef; - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('openDialog', () => { - beforeEach(() => { - spyOn(launchDialogService, 'launch').and.returnValue(of(componentRef)); - }); - - it('should call LaunchDialogService launch', () => { - service.openDialog(undefined, component.vcr, { test: 123 }); - - expect(launchDialogService.launch).toHaveBeenCalledWith( - LAUNCH_CALLER.SAVED_CART, - component.vcr, - { - test: 123, - } - ); - }); - - it('should call LaunchDialogService clear on close', () => { - spyOn(launchDialogService, 'clear'); - - const comp = service.openDialog(undefined, component.vcr); - comp?.subscribe(); - - expect(launchDialogService.clear).toHaveBeenCalledWith( - LAUNCH_CALLER.SAVED_CART - ); - }); - - it('should destroy component on close', () => { - spyOn(componentRef, 'destroy'); - - const comp = service.openDialog(undefined, component.vcr); - comp?.subscribe(); - - expect(componentRef.destroy).toHaveBeenCalled(); - }); - }); -}); diff --git a/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/saved-cart-form-launch-dialog.service.ts b/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/saved-cart-form-launch-dialog.service.ts deleted file mode 100644 index a950ea8b2b0..00000000000 --- a/feature-libs/cart/saved-cart/components/saved-cart-form-dialog/saved-cart-form-launch-dialog.service.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { ElementRef, Injectable, ViewContainerRef } from '@angular/core'; -import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; -import { combineLatest, Observable } from 'rxjs'; -import { filter, map, tap } from 'rxjs/operators'; - -// TODO(#12167): deprecations cleanup -/** - * @deprecated since 3.3 - use `LaunchDialogService` instead - */ -@Injectable({ providedIn: 'root' }) -export class SavedCartFormLaunchDialogService { - constructor(protected launchDialogService: LaunchDialogService) {} - - /** - * @deprecated since 3.3 - use `LaunchDialogService.openDialog` with LAUNCH_CALLER.SAVED_CART instead - */ - openDialog( - openElement?: ElementRef, - vcr?: ViewContainerRef, - data?: any - ): Observable | undefined { - const component = this.launchDialogService.launch( - LAUNCH_CALLER.SAVED_CART, - vcr, - data - ); - - if (component) { - return combineLatest([ - component, - this.launchDialogService.dialogClose, - ]).pipe( - filter(([, close]) => close !== undefined), - tap(([comp]) => { - openElement?.nativeElement.focus(); - this.launchDialogService.clear(LAUNCH_CALLER.SAVED_CART); - comp.destroy(); - }), - map(([comp]) => comp) - ); - } - } -} diff --git a/feature-libs/cart/schematics/add-cart/index_spec.ts b/feature-libs/cart/schematics/add-cart/index_spec.ts index 864e3456c22..55fc9ebeb43 100644 --- a/feature-libs/cart/schematics/add-cart/index_spec.ts +++ b/feature-libs/cart/schematics/add-cart/index_spec.ts @@ -45,7 +45,6 @@ describe('Spartacus Cart schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/feature-libs/organization/schematics/add-organization/index_spec.ts b/feature-libs/organization/schematics/add-organization/index_spec.ts index 937202f2704..fe1ef709d4a 100644 --- a/feature-libs/organization/schematics/add-organization/index_spec.ts +++ b/feature-libs/organization/schematics/add-organization/index_spec.ts @@ -49,7 +49,6 @@ describe('Spartacus Organization schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/feature-libs/product/schematics/add-product/index_spec.ts b/feature-libs/product/schematics/add-product/index_spec.ts index cbf21f9957c..29ec9ff58d1 100644 --- a/feature-libs/product/schematics/add-product/index_spec.ts +++ b/feature-libs/product/schematics/add-product/index_spec.ts @@ -48,7 +48,6 @@ describe('Spartacus Product schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/feature-libs/qualtrics/schematics/add-qualtrics/index_spec.ts b/feature-libs/qualtrics/schematics/add-qualtrics/index_spec.ts index 4d489fb6408..e3170218510 100644 --- a/feature-libs/qualtrics/schematics/add-qualtrics/index_spec.ts +++ b/feature-libs/qualtrics/schematics/add-qualtrics/index_spec.ts @@ -45,7 +45,6 @@ describe('Spartacus Qualtrics schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/feature-libs/smartedit/schematics/add-smartedit/index_spec.ts b/feature-libs/smartedit/schematics/add-smartedit/index_spec.ts index 7cd3c816f1a..7436c0b96ab 100644 --- a/feature-libs/smartedit/schematics/add-smartedit/index_spec.ts +++ b/feature-libs/smartedit/schematics/add-smartedit/index_spec.ts @@ -44,7 +44,6 @@ describe('Spartacus SmartEdit schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/feature-libs/storefinder/schematics/add-storefinder/index_spec.ts b/feature-libs/storefinder/schematics/add-storefinder/index_spec.ts index 9388bd8ed18..47959061b2e 100644 --- a/feature-libs/storefinder/schematics/add-storefinder/index_spec.ts +++ b/feature-libs/storefinder/schematics/add-storefinder/index_spec.ts @@ -45,7 +45,6 @@ describe('Spartacus Storefinder schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/feature-libs/tracking/schematics/add-tracking/index_spec.ts b/feature-libs/tracking/schematics/add-tracking/index_spec.ts index d9c49016593..f77dc3e94eb 100644 --- a/feature-libs/tracking/schematics/add-tracking/index_spec.ts +++ b/feature-libs/tracking/schematics/add-tracking/index_spec.ts @@ -48,7 +48,6 @@ describe('Spartacus Tracking schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/feature-libs/user/schematics/add-user/index_spec.ts b/feature-libs/user/schematics/add-user/index_spec.ts index 47337eeeb75..25a446c93cd 100644 --- a/feature-libs/user/schematics/add-user/index_spec.ts +++ b/feature-libs/user/schematics/add-user/index_spec.ts @@ -49,7 +49,6 @@ describe('Spartacus User schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/integration-libs/cdc/schematics/add-cdc/index_spec.ts b/integration-libs/cdc/schematics/add-cdc/index_spec.ts index 58c8ab87737..a17aa8b78c8 100644 --- a/integration-libs/cdc/schematics/add-cdc/index_spec.ts +++ b/integration-libs/cdc/schematics/add-cdc/index_spec.ts @@ -49,7 +49,6 @@ describe('Spartacus CDC schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/integration-libs/cds/src/schematics/add-cds/index_spec.ts b/integration-libs/cds/src/schematics/add-cds/index_spec.ts index 95a5f7ac2cc..cd1980cf2e4 100644 --- a/integration-libs/cds/src/schematics/add-cds/index_spec.ts +++ b/integration-libs/cds/src/schematics/add-cds/index_spec.ts @@ -48,7 +48,6 @@ describe('Spartacus CDS schematics: ng-add', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/projects/assets/src/translations/en/asm.ts b/projects/assets/src/translations/en/asm.ts deleted file mode 100644 index 3241f1ee264..00000000000 --- a/projects/assets/src/translations/en/asm.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @deprecated since 3.2, use asm lib instead - */ -export const asm = { - asm: { - mainLogoLabel: 'SAP', - mainTitle: 'Assisted Service Mode', - logout: 'Sign Out', - hideUi: 'Close ASM', - toggleUi: { - collapse: 'Hide ASM', - expand: 'Show ASM', - }, - loginForm: { - submit: 'Sign In', - userId: { - label: 'Agent ID', - required: 'Agent ID is required', - }, - password: { - label: 'Password', - required: 'Password is required', - }, - }, - customerSearch: { - searchTerm: { - label: 'Customer Name/Email Address', - }, - submit: 'Start Session', - noMatch: 'No customer found.', - }, - csagentTokenExpired: 'Your customer support agent session is expired.', - endSession: 'End Session', - agentSessionTimer: { - label: 'Session Timeout', - minutes: 'min', - reset: 'Reset', - }, - standardSessionInProgress: 'Standard customer session in progress.', - auth: { - agentLoggedInError: - 'Cannot login as user when there is an active CS agent session. Please either emulate user or logout CS agent.', - }, - error: { - noCustomerId: - 'No customerId found for selected user. Session cannot be started.', - }, - }, -}; diff --git a/projects/assets/src/translations/en/index.ts b/projects/assets/src/translations/en/index.ts index db594bfc4be..40d34684a77 100644 --- a/projects/assets/src/translations/en/index.ts +++ b/projects/assets/src/translations/en/index.ts @@ -1,5 +1,4 @@ import { address } from './address'; -import { asm } from './asm'; import { cart } from './cart'; import { checkout } from './checkout'; import { common } from './common'; @@ -11,7 +10,6 @@ import { user } from './user'; export const en = { address, - asm, cart, checkout, common, diff --git a/projects/core/public_api.ts b/projects/core/public_api.ts index d8fbd714c1e..9543d99c08c 100644 --- a/projects/core/public_api.ts +++ b/projects/core/public_api.ts @@ -2,7 +2,6 @@ * Public API Surface of core */ export * from './src/anonymous-consents/index'; -export * from './src/asm/index'; export * from './src/auth/index'; export * from './src/cart/index'; export * from './src/checkout/index'; @@ -15,7 +14,6 @@ export * from './src/i18n/index'; export * from './src/model/index'; export * from './src/cost-center/index'; export * from './src/occ/index'; -export * from './src/personalization/index'; export * from './src/process/index'; export * from './src/product/index'; export * from './src/routing/index'; diff --git a/projects/core/src/asm/asm.module.ts b/projects/core/src/asm/asm.module.ts deleted file mode 100644 index f71256c7b97..00000000000 --- a/projects/core/src/asm/asm.module.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { APP_INITIALIZER, ModuleWithProviders, NgModule } from '@angular/core'; -import { AuthService } from '../auth/user-auth/facade/auth.service'; -import { AuthHttpHeaderService } from '../auth/user-auth/services/auth-http-header.service'; -import { AuthStorageService } from '../auth/user-auth/services/auth-storage.service'; -import { provideDefaultConfig } from '../config/config-providers'; -import { defaultAsmConfig } from './config/default-asm-config'; -import { AsmAuthHttpHeaderService } from './services/asm-auth-http-header.service'; -import { AsmAuthStorageService } from './services/asm-auth-storage.service'; -import { AsmAuthService } from './services/asm-auth.service'; -import { AsmStatePersistenceService } from './services/asm-state-persistence.service'; -import { AsmStoreModule } from './store/asm-store.module'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export function asmStatePersistenceFactory( - asmStatePersistenceService: AsmStatePersistenceService -) { - const result = () => asmStatePersistenceService.initSync(); - return result; -} - -/** - * @deprecated since 3.2, use asm lib instead - */ -@NgModule({ - imports: [CommonModule, AsmStoreModule], -}) -export class AsmModule { - static forRoot(): ModuleWithProviders { - return { - ngModule: AsmModule, - providers: [ - provideDefaultConfig(defaultAsmConfig), - { - provide: AuthStorageService, - useExisting: AsmAuthStorageService, - }, - { - provide: AuthService, - useExisting: AsmAuthService, - }, - { - provide: AuthHttpHeaderService, - useExisting: AsmAuthHttpHeaderService, - }, - { - provide: APP_INITIALIZER, - useFactory: asmStatePersistenceFactory, - deps: [AsmStatePersistenceService], - multi: true, - }, - ], - }; - } -} diff --git a/projects/core/src/asm/config/asm-config.ts b/projects/core/src/asm/config/asm-config.ts deleted file mode 100644 index 0af84447363..00000000000 --- a/projects/core/src/asm/config/asm-config.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Config } from '../../config/config-tokens'; -import { OccConfig } from '../../occ/config/occ-config'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -@Injectable({ - providedIn: 'root', - useExisting: Config, -}) -export abstract class AsmConfig extends OccConfig { - asm?: { - agentSessionTimer?: { - startingDelayInSeconds?: number; - }; - customerSearch?: { - maxResults?: number; - }; - }; -} diff --git a/projects/core/src/asm/config/default-asm-config.ts b/projects/core/src/asm/config/default-asm-config.ts deleted file mode 100644 index d1e900528b6..00000000000 --- a/projects/core/src/asm/config/default-asm-config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { AsmConfig } from './asm-config'; - -export const defaultAsmConfig: AsmConfig = { - asm: { - agentSessionTimer: { - startingDelayInSeconds: 600, - }, - customerSearch: { - maxResults: 20, - }, - }, -}; diff --git a/projects/core/src/asm/connectors/asm.adapter.ts b/projects/core/src/asm/connectors/asm.adapter.ts deleted file mode 100644 index 61d8d0ac4c0..00000000000 --- a/projects/core/src/asm/connectors/asm.adapter.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Observable } from 'rxjs'; -import { - CustomerSearchOptions, - CustomerSearchPage, -} from '../models/asm.models'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export abstract class AsmAdapter { - /** - * Abstract function used to search for customers. - */ - abstract customerSearch( - options: CustomerSearchOptions - ): Observable; -} diff --git a/projects/core/src/asm/connectors/asm.connector.spec.ts b/projects/core/src/asm/connectors/asm.connector.spec.ts deleted file mode 100644 index 8d260c64626..00000000000 --- a/projects/core/src/asm/connectors/asm.connector.spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { Observable, of } from 'rxjs'; -import { - CustomerSearchOptions, - CustomerSearchPage, -} from '../models/asm.models'; -import { AsmAdapter } from './asm.adapter'; -import { AsmConnector } from './asm.connector'; - -class MockAsmAdapter { - customerSearch( - _options: CustomerSearchOptions - ): Observable { - return of(); - } -} - -const testSearchOptions: CustomerSearchOptions = { query: 'abcde' }; -const testSearchResults: CustomerSearchPage = { - entries: [ - { - name: 'test-name', - uid: 'test-uid', - customerId: 'test-customerId', - displayUid: 'test-displayUid', - firstName: 'test-firstName', - lastName: 'test-lastName', - }, - { - name: 'test-name', - uid: 'test-uid', - customerId: 'test-customerId', - displayUid: 'test-displayUid', - firstName: 'test-firstName', - lastName: 'test-lastName', - }, - ], - pagination: { - currentPage: 0, - pageSize: 20, - }, -} as CustomerSearchPage; - -describe('AsmConnector', () => { - let asmConnector: AsmConnector; - let asmAdapter: AsmAdapter; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{ provide: AsmAdapter, useClass: MockAsmAdapter }], - }); - - asmConnector = TestBed.inject(AsmConnector); - asmAdapter = TestBed.inject(AsmAdapter); - }); - - it('should be created', () => { - expect(asmConnector).toBeTruthy(); - }); - - it('should call adapter for customerSearch', () => { - spyOn(asmAdapter, 'customerSearch').and.stub(); - asmConnector.customerSearch(testSearchOptions); - expect(asmAdapter.customerSearch).toHaveBeenCalledWith(testSearchOptions); - }); - - it('should return customerSearch results ', () => { - spyOn(asmAdapter, 'customerSearch').and.returnValue(of(testSearchResults)); - let results: CustomerSearchPage; - asmConnector - .customerSearch(testSearchOptions) - .subscribe((value) => (results = value)) - .unsubscribe(); - expect(results).toEqual(testSearchResults); - }); -}); diff --git a/projects/core/src/asm/connectors/asm.connector.ts b/projects/core/src/asm/connectors/asm.connector.ts deleted file mode 100644 index d4478e49a2e..00000000000 --- a/projects/core/src/asm/connectors/asm.connector.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { - CustomerSearchOptions, - CustomerSearchPage, -} from '../models/asm.models'; -import { AsmAdapter } from './asm.adapter'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -@Injectable({ - providedIn: 'root', -}) -export class AsmConnector { - constructor(protected asmAdapter: AsmAdapter) {} - - customerSearch( - options: CustomerSearchOptions - ): Observable { - return this.asmAdapter.customerSearch(options); - } -} diff --git a/projects/core/src/asm/connectors/converters.ts b/projects/core/src/asm/connectors/converters.ts deleted file mode 100644 index d2ae7af315d..00000000000 --- a/projects/core/src/asm/connectors/converters.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { InjectionToken } from '@angular/core'; -import { Converter } from '../../util/converter.service'; -import { CustomerSearchPage } from '../models/asm.models'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const CUSTOMER_SEARCH_PAGE_NORMALIZER = new InjectionToken< - Converter ->('CustomerSearchPageNormalizer'); diff --git a/projects/core/src/asm/connectors/index.ts b/projects/core/src/asm/connectors/index.ts deleted file mode 100644 index 5702d8822e8..00000000000 --- a/projects/core/src/asm/connectors/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './asm.adapter'; -export * from './asm.connector'; -export * from './converters'; diff --git a/projects/core/src/asm/facade/asm.service.spec.ts b/projects/core/src/asm/facade/asm.service.spec.ts deleted file mode 100644 index cb00789f76d..00000000000 --- a/projects/core/src/asm/facade/asm.service.spec.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { Store, StoreModule } from '@ngrx/store'; -import { User } from '../../model/misc.model'; -import { - AsmUi, - CustomerSearchOptions, - CustomerSearchPage, -} from '../models/asm.models'; -import { AsmActions } from '../store/actions/index'; -import { ASM_FEATURE, AsmState } from '../store/asm-state'; -import * as fromReducers from '../store/reducers/index'; -import { AsmService } from './asm.service'; - -const mockUser: User = { - displayUid: 'Display Uid', - firstName: 'First', - lastName: 'Last', - name: 'First Last', - uid: 'user@test.com', - customerId: '123456', -}; - -const mockCustomerSearchPage: CustomerSearchPage = { - entries: [mockUser], -}; - -describe('AsmService', () => { - let service: AsmService; - let store: Store; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({}), - StoreModule.forFeature(ASM_FEATURE, fromReducers.getReducers()), - ], - providers: [AsmService], - }); - - service = TestBed.inject(AsmService); - store = TestBed.inject(Store); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - it('should dispatch proper action for customer search', () => { - spyOn(store, 'dispatch').and.stub(); - const searchOptions: CustomerSearchOptions = { query: 'search term' }; - service.customerSearch(searchOptions); - expect(store.dispatch).toHaveBeenCalledWith( - new AsmActions.CustomerSearch(searchOptions) - ); - }); - - it('should return search result', () => { - store.dispatch( - new AsmActions.CustomerSearchSuccess(mockCustomerSearchPage) - ); - - let result: CustomerSearchPage; - service - .getCustomerSearchResults() - .subscribe((value) => (result = value)) - .unsubscribe(); - expect(result).toEqual(mockCustomerSearchPage); - }); - - it('should return search result loading status', () => { - let result: boolean; - service - .getCustomerSearchResultsLoading() - .subscribe((value) => (result = value)) - .unsubscribe(); - expect(result).toEqual(false); - }); - - it('should dispatch proper action for customer search reset', () => { - spyOn(store, 'dispatch').and.stub(); - service.customerSearchReset(); - expect(store.dispatch).toHaveBeenCalledWith( - new AsmActions.CustomerSearchReset() - ); - }); - - it('should dispatch proper action for update asm UI', () => { - spyOn(store, 'dispatch').and.stub(); - const asmUi: AsmUi = {}; - service.updateAsmUiState(asmUi); - expect(store.dispatch).toHaveBeenCalledWith( - new AsmActions.AsmUiUpdate(asmUi) - ); - }); - - it('should get the AsmUi state', () => { - const asmUi: AsmUi = { collapsed: false }; - store.dispatch(new AsmActions.AsmUiUpdate(asmUi)); - - let result: AsmUi; - service - .getAsmUiState() - .subscribe((value) => (result = value)) - .unsubscribe(); - expect(result).toEqual(asmUi); - }); -}); diff --git a/projects/core/src/asm/facade/asm.service.ts b/projects/core/src/asm/facade/asm.service.ts deleted file mode 100644 index 778ae292114..00000000000 --- a/projects/core/src/asm/facade/asm.service.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Injectable } from '@angular/core'; -import { select, Store } from '@ngrx/store'; -import { Observable } from 'rxjs'; -import { - AsmUi, - CustomerSearchOptions, - CustomerSearchPage, -} from '../models/asm.models'; -import { AsmActions } from '../store/actions/index'; -import { StateWithAsm } from '../store/asm-state'; -import { AsmSelectors } from '../store/index'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -@Injectable({ - providedIn: 'root', -}) -export class AsmService { - constructor(protected store: Store) {} - - /** - * Search for customers - * @param options - */ - customerSearch(options: CustomerSearchOptions): void { - this.store.dispatch(new AsmActions.CustomerSearch(options)); - } - - /** - * Reset the customer search result data to the initial state. - */ - customerSearchReset(): void { - this.store.dispatch(new AsmActions.CustomerSearchReset()); - } - - /** - * Returns the customer search result data. - */ - getCustomerSearchResults(): Observable { - return this.store.pipe(select(AsmSelectors.getCustomerSearchResults)); - } - - /** - * Returns the customer search result loading status. - */ - getCustomerSearchResultsLoading(): Observable { - return this.store.pipe( - select(AsmSelectors.getCustomerSearchResultsLoading) - ); - } - - /** - * Updates the state of the ASM UI - */ - updateAsmUiState(asmUi: AsmUi): void { - this.store.dispatch(new AsmActions.AsmUiUpdate(asmUi)); - } - - /** - * Get the state of the ASM UI - */ - getAsmUiState(): Observable { - return this.store.pipe(select(AsmSelectors.getAsmUi)); - } -} diff --git a/projects/core/src/asm/facade/csagent-auth.service.spec.ts b/projects/core/src/asm/facade/csagent-auth.service.spec.ts deleted file mode 100644 index 0f892ecc417..00000000000 --- a/projects/core/src/asm/facade/csagent-auth.service.spec.ts +++ /dev/null @@ -1,308 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { Store, StoreModule } from '@ngrx/store'; -import { TokenResponse } from 'angular-oauth2-oidc'; -import { of } from 'rxjs'; -import { take } from 'rxjs/operators'; -import { AuthActions, AuthToken } from '../../auth'; -import { AuthService } from '../../auth/user-auth/facade/auth.service'; -import { UserIdService } from '../../auth/user-auth/facade/user-id.service'; -import { OAuthLibWrapperService } from '../../auth/user-auth/services/oauth-lib-wrapper.service'; -import { - OCC_USER_ID_ANONYMOUS, - OCC_USER_ID_CURRENT, -} from '../../occ/utils/occ-constants'; -import { UserService } from '../../user/facade/user.service'; -import { - AsmAuthStorageService, - TokenTarget, -} from '../services/asm-auth-storage.service'; -import { AsmActions } from '../store'; -import { AsmState, ASM_FEATURE } from '../store/asm-state'; -import * as fromReducers from '../store/reducers/index'; -import { CsAgentAuthService } from './csagent-auth.service'; - -class MockAuthService implements Partial { - logout() {} -} - -class MockOAuthLibWrapperService implements Partial { - authorizeWithPasswordFlow() { - return Promise.resolve({} as TokenResponse); - } - revokeAndLogout() { - return Promise.resolve(); - } -} - -class MockUserService implements Partial { - get() { - return of({}); - } -} - -describe('CsAgentAuthService', () => { - let service: CsAgentAuthService; - let store: Store; - let userIdService: UserIdService; - let authService: AuthService; - let asmAuthStorageService: AsmAuthStorageService; - let oAuthLibWrapperService: OAuthLibWrapperService; - let userService: UserService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({}), - StoreModule.forFeature(ASM_FEATURE, fromReducers.getReducers()), - ], - providers: [ - AsmAuthStorageService, - UserIdService, - { provide: AuthService, useClass: MockAuthService }, - { - provide: OAuthLibWrapperService, - useClass: MockOAuthLibWrapperService, - }, - { provide: UserService, useClass: MockUserService }, - ], - }); - - service = TestBed.inject(CsAgentAuthService); - userIdService = TestBed.inject(UserIdService); - authService = TestBed.inject(AuthService); - asmAuthStorageService = TestBed.inject(AsmAuthStorageService); - oAuthLibWrapperService = TestBed.inject(OAuthLibWrapperService); - userService = TestBed.inject(UserService); - store = TestBed.inject(Store); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('authorizeCustomerSupportAgent()', () => { - it('should only login cs agent when there is not any active session', async () => { - spyOn( - oAuthLibWrapperService, - 'authorizeWithPasswordFlow' - ).and.callThrough(); - spyOn(store, 'dispatch').and.callFake(() => {}); - spyOn(userIdService, 'setUserId').and.callThrough(); - spyOn(asmAuthStorageService, 'clearEmulatedUserToken').and.callThrough(); - - await service.authorizeCustomerSupportAgent('testUser', 'testPass'); - - let tokenTarget; - asmAuthStorageService - .getTokenTarget() - .pipe(take(1)) - .subscribe((target) => (tokenTarget = target)); - - expect( - oAuthLibWrapperService.authorizeWithPasswordFlow - ).toHaveBeenCalledWith('testUser', 'testPass'); - expect(tokenTarget).toBe(TokenTarget.CSAgent); - expect(store.dispatch).toHaveBeenCalledWith(new AuthActions.Logout()); - expect(userIdService.setUserId).toHaveBeenCalledWith( - OCC_USER_ID_ANONYMOUS - ); - expect(asmAuthStorageService.clearEmulatedUserToken).toHaveBeenCalled(); - }); - - it('when there was logged in user, should login CS agent and start emulation for that user', async () => { - const dispatch = spyOn(store, 'dispatch').and.callFake(() => {}); - spyOn( - oAuthLibWrapperService, - 'authorizeWithPasswordFlow' - ).and.callThrough(); - spyOn(userIdService, 'setUserId').and.callThrough(); - spyOn(asmAuthStorageService, 'setEmulatedUserToken').and.callThrough(); - spyOn(userService, 'get').and.returnValue(of({ customerId: 'custId' })); - asmAuthStorageService.setToken({ access_token: 'token' } as AuthToken); - - await service.authorizeCustomerSupportAgent('testUser', 'testPass'); - - let tokenTarget; - asmAuthStorageService - .getTokenTarget() - .pipe(take(1)) - .subscribe((target) => (tokenTarget = target)); - - expect( - oAuthLibWrapperService.authorizeWithPasswordFlow - ).toHaveBeenCalledWith('testUser', 'testPass'); - expect(tokenTarget).toBe(TokenTarget.CSAgent); - expect(dispatch.calls.argsFor(0)[0]).toEqual(new AuthActions.Logout()); - expect(dispatch.calls.argsFor(1)[0]).toEqual(new AuthActions.Login()); - - expect(userIdService.setUserId).toHaveBeenCalledWith('custId'); - expect(asmAuthStorageService.setEmulatedUserToken).toHaveBeenCalledWith({ - access_token: 'token', - } as AuthToken); - }); - - it('should not changed storage state, when authorization failed', async () => { - spyOn(store, 'dispatch').and.callFake(() => {}); - spyOn(oAuthLibWrapperService, 'authorizeWithPasswordFlow').and.callFake( - () => { - return Promise.reject(); - } - ); - spyOn(userIdService, 'setUserId').and.callThrough(); - spyOn(asmAuthStorageService, 'setEmulatedUserToken').and.callThrough(); - spyOn(asmAuthStorageService, 'clearEmulatedUserToken').and.callThrough(); - - await service.authorizeCustomerSupportAgent('testUser', 'testPass'); - - let tokenTarget; - asmAuthStorageService - .getTokenTarget() - .pipe(take(1)) - .subscribe((target) => (tokenTarget = target)); - - expect( - oAuthLibWrapperService.authorizeWithPasswordFlow - ).toHaveBeenCalledWith('testUser', 'testPass'); - expect(tokenTarget).toBe(TokenTarget.User); - expect(store.dispatch).not.toHaveBeenCalled(); - expect(userIdService.setUserId).not.toHaveBeenCalled(); - expect(asmAuthStorageService.setEmulatedUserToken).not.toHaveBeenCalled(); - expect( - asmAuthStorageService.clearEmulatedUserToken - ).not.toHaveBeenCalled(); - }); - }); - - describe('startCustomerEmulationSession()', () => { - it('should start emulation of a customer', () => { - const dispatch = spyOn(store, 'dispatch').and.callFake(() => {}); - spyOn(asmAuthStorageService, 'clearEmulatedUserToken').and.callThrough(); - spyOn(userIdService, 'setUserId').and.callThrough(); - - service.startCustomerEmulationSession('custId'); - - expect(asmAuthStorageService.clearEmulatedUserToken).toHaveBeenCalled(); - expect(dispatch.calls.argsFor(0)[0]).toEqual(new AuthActions.Logout()); - expect(dispatch.calls.argsFor(1)[0]).toEqual(new AuthActions.Login()); - expect(userIdService.setUserId).toHaveBeenCalledWith('custId'); - }); - }); - - describe('isCustomerSupportAgentLoggedIn()', () => { - it('should emit true when CS agent is logged in', (done) => { - asmAuthStorageService.switchTokenTargetToCSAgent(); - asmAuthStorageService.setToken({ access_token: 'token' } as AuthToken); - - service - .isCustomerSupportAgentLoggedIn() - .pipe(take(1)) - .subscribe((result) => { - expect(result).toBe(true); - done(); - }); - }); - - it('should emit false when user logged in', (done) => { - asmAuthStorageService.switchTokenTargetToUser(); - - service - .isCustomerSupportAgentLoggedIn() - .pipe(take(1)) - .subscribe((result) => { - expect(result).toBe(false); - done(); - }); - }); - - it('should emit false when no one is logged in', (done) => { - asmAuthStorageService.setToken(undefined); - - service - .isCustomerSupportAgentLoggedIn() - .pipe(take(1)) - .subscribe((result) => { - expect(result).toBe(false); - done(); - }); - }); - }); - - describe('isCustomerEmulated()', () => { - it('should emit true when user is emulated', (done) => { - userIdService.setUserId('cust-id'); - - service - .isCustomerEmulated() - .pipe(take(1)) - .subscribe((result) => { - expect(result).toBe(true); - done(); - }); - }); - - it('should emit false when user is not emulated', (done) => { - userIdService.setUserId(OCC_USER_ID_CURRENT); - - service - .isCustomerEmulated() - .pipe(take(1)) - .subscribe((result) => { - expect(result).toBe(false); - done(); - }); - }); - }); - - // TODO(#8248) - xdescribe('getCustomerSupportAgentTokenLoading()', () => {}); - - describe('logoutCustomerSupportAgent()', () => { - it('should logout CS agent', async () => { - const dispatch = spyOn(store, 'dispatch').and.callFake(() => {}); - spyOn(oAuthLibWrapperService, 'revokeAndLogout').and.callThrough(); - - await service.logoutCustomerSupportAgent(); - - let tokenTarget; - asmAuthStorageService - .getTokenTarget() - .pipe(take(1)) - .subscribe((target) => (tokenTarget = target)); - - expect(oAuthLibWrapperService.revokeAndLogout).toHaveBeenCalled(); - expect(dispatch).toHaveBeenCalledWith( - new AsmActions.LogoutCustomerSupportAgent() - ); - expect(tokenTarget).toBe(TokenTarget.User); - }); - - it('should restore previous session when there is old session token', async () => { - const dispatch = spyOn(store, 'dispatch').and.callFake(() => {}); - spyOn(asmAuthStorageService, 'setToken').and.callThrough(); - spyOn(asmAuthStorageService, 'clearEmulatedUserToken').and.callThrough(); - spyOn(userIdService, 'setUserId').and.callThrough(); - userIdService.setUserId('cust-id'); - asmAuthStorageService.setEmulatedUserToken({ - access_token: 'user_token', - } as AuthToken); - - await service.logoutCustomerSupportAgent(); - - expect(asmAuthStorageService.setToken).toHaveBeenCalledWith({ - access_token: 'user_token', - } as AuthToken); - expect(userIdService.setUserId).toHaveBeenCalledWith(OCC_USER_ID_CURRENT); - expect(asmAuthStorageService.clearEmulatedUserToken).toHaveBeenCalled(); - expect(dispatch.calls.argsFor(1)[0]).toEqual(new AuthActions.Logout()); - expect(dispatch.calls.argsFor(2)[0]).toEqual(new AuthActions.Login()); - }); - - it('should logout user, when we can not restore old session', async () => { - spyOn(authService, 'logout').and.callThrough(); - - await service.logoutCustomerSupportAgent(); - - expect(authService.logout).toHaveBeenCalled(); - }); - }); -}); diff --git a/projects/core/src/asm/facade/csagent-auth.service.ts b/projects/core/src/asm/facade/csagent-auth.service.ts deleted file mode 100644 index cde20b5865a..00000000000 --- a/projects/core/src/asm/facade/csagent-auth.service.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { combineLatest, Observable, of } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { AuthService } from '../../auth/user-auth/facade/auth.service'; -import { UserIdService } from '../../auth/user-auth/facade/user-id.service'; -import { OAuthLibWrapperService } from '../../auth/user-auth/services/oauth-lib-wrapper.service'; -import { AuthActions } from '../../auth/user-auth/store/actions'; -import { - OCC_USER_ID_ANONYMOUS, - OCC_USER_ID_CURRENT, -} from '../../occ/utils/occ-constants'; -import { UserService } from '../../user/facade/user.service'; -import { - AsmAuthStorageService, - TokenTarget, -} from '../services/asm-auth-storage.service'; -import { AsmActions } from '../store/actions'; -import { StateWithAsm } from '../store/asm-state'; - -/** - * @deprecated since 3.2, use asm lib instead - * - * Auth service for CS agent. Useful to login/logout agent, start emulation - * or get information about the status of emulation. - */ -@Injectable({ - providedIn: 'root', -}) -export class CsAgentAuthService { - constructor( - protected authService: AuthService, - protected authStorageService: AsmAuthStorageService, - protected userIdService: UserIdService, - protected oAuthLibWrapperService: OAuthLibWrapperService, - protected store: Store, - protected userService: UserService - ) {} - - /** - * Loads access token for a customer support agent. - * @param userId - * @param password - */ - async authorizeCustomerSupportAgent( - userId: string, - password: string - ): Promise { - let userToken; - this.authStorageService - .getToken() - .subscribe((token) => (userToken = token)) - .unsubscribe(); - - this.authStorageService.switchTokenTargetToCSAgent(); - try { - await this.oAuthLibWrapperService.authorizeWithPasswordFlow( - userId, - password - ); - // Start emulation for currently logged in user - let customerId: string; - this.userService - .get() - .subscribe((user) => (customerId = user?.customerId)) - .unsubscribe(); - this.store.dispatch(new AuthActions.Logout()); - - if (Boolean(customerId)) { - // OCC specific user id handling. Customize when implementing different backend - this.userIdService.setUserId(customerId); - this.authStorageService.setEmulatedUserToken(userToken); - this.store.dispatch(new AuthActions.Login()); - } else { - // When we can't get the customerId just end all current sessions - this.userIdService.setUserId(OCC_USER_ID_ANONYMOUS); - this.authStorageService.clearEmulatedUserToken(); - } - } catch { - this.authStorageService.switchTokenTargetToUser(); - } - } - - /** - * Starts an ASM customer emulation session. - * A customer emulation session is stopped by calling logout(). - * @param customerId - */ - public startCustomerEmulationSession(customerId: string): void { - this.authStorageService.clearEmulatedUserToken(); - - // OCC specific user id handling. Customize when implementing different backend - this.store.dispatch(new AuthActions.Logout()); - this.userIdService.setUserId(customerId); - this.store.dispatch(new AuthActions.Login()); - } - - /** - * Check if CS agent is currently logged in. - * - * @returns observable emitting true when CS agent is logged in or false when not. - */ - public isCustomerSupportAgentLoggedIn(): Observable { - return combineLatest([ - this.authStorageService.getToken(), - this.authStorageService.getTokenTarget(), - ]).pipe( - map(([token, tokenTarget]) => - Boolean(token?.access_token && tokenTarget === TokenTarget.CSAgent) - ) - ); - } - - /** - * Utility function to determine if customer is emulated. - * - * @returns observable emitting true when there is active emulation session or false when not. - */ - public isCustomerEmulated(): Observable { - return this.userIdService.isEmulated(); - } - - /** - * Returns the customer support agent's token loading status - */ - public getCustomerSupportAgentTokenLoading(): Observable { - // TODO(#8248): Create new loading state outside of store - return of(false); - } - - /** - * Logout a customer support agent. - */ - async logoutCustomerSupportAgent(): Promise { - const emulatedToken = this.authStorageService.getEmulatedUserToken(); - - let isCustomerEmulated; - this.userIdService - .isEmulated() - .subscribe((emulated) => (isCustomerEmulated = emulated)) - .unsubscribe(); - - await this.oAuthLibWrapperService.revokeAndLogout(); - - this.store.dispatch(new AsmActions.LogoutCustomerSupportAgent()); - this.authStorageService.setTokenTarget(TokenTarget.User); - - if (isCustomerEmulated && emulatedToken) { - this.store.dispatch(new AuthActions.Logout()); - this.authStorageService.setToken(emulatedToken); - this.userIdService.setUserId(OCC_USER_ID_CURRENT); - this.authStorageService.clearEmulatedUserToken(); - this.store.dispatch(new AuthActions.Login()); - } else { - this.authService.logout(); - } - } -} diff --git a/projects/core/src/asm/facade/index.ts b/projects/core/src/asm/facade/index.ts deleted file mode 100644 index 01c8034b870..00000000000 --- a/projects/core/src/asm/facade/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './asm.service'; -export * from './csagent-auth.service'; diff --git a/projects/core/src/asm/index.ts b/projects/core/src/asm/index.ts deleted file mode 100644 index 82e18936542..00000000000 --- a/projects/core/src/asm/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export { AsmModule } from './asm.module'; -export * from './config/asm-config'; -export * from './connectors/index'; -export * from './facade/index'; -export * from './models/asm.models'; -export * from './services/index'; -export * from './store/actions/index'; -export * from './store/asm-state'; -export * from './store/selectors/index'; diff --git a/projects/core/src/asm/models/asm.models.ts b/projects/core/src/asm/models/asm.models.ts deleted file mode 100644 index 60dcf20a986..00000000000 --- a/projects/core/src/asm/models/asm.models.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { PaginationModel, SortModel, User } from '../../model/misc.model'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export interface CustomerSearchPage { - entries: User[]; - pagination?: PaginationModel; - sorts?: SortModel[]; -} - -/** - * @deprecated since 3.2, use asm lib instead - */ -export interface CustomerSearchOptions { - query?: string; - pageSize?: number; -} - -/** - * @deprecated since 3.2, use asm lib instead - */ -export interface AsmUi { - collapsed?: boolean; -} diff --git a/projects/core/src/asm/services/asm-auth-http-header.service.spec.ts b/projects/core/src/asm/services/asm-auth-http-header.service.spec.ts deleted file mode 100644 index caa8af5f7a1..00000000000 --- a/projects/core/src/asm/services/asm-auth-http-header.service.spec.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { HttpHeaders, HttpRequest } from '@angular/common/http'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; -import { TestBed } from '@angular/core/testing'; -import { of } from 'rxjs'; -import { AuthService } from '../../auth/user-auth/facade/auth.service'; -import { AuthToken } from '../../auth/user-auth/models/auth-token.model'; -import { AuthStorageService } from '../../auth/user-auth/services/auth-storage.service'; -import { OAuthLibWrapperService } from '../../auth/user-auth/services/oauth-lib-wrapper.service'; -import { GlobalMessageService } from '../../global-message/facade/global-message.service'; -import { GlobalMessageType } from '../../global-message/models/global-message.model'; -import { OccEndpointsService } from '../../occ/services/occ-endpoints.service'; -import { RoutingService } from '../../routing/facade/routing.service'; -import { CsAgentAuthService } from '../facade/csagent-auth.service'; -import { AsmAuthHttpHeaderService } from './asm-auth-http-header.service'; - -class MockCsAgentAuthService implements Partial { - isCustomerSupportAgentLoggedIn() { - return of(false); - } - logoutCustomerSupportAgent() { - return Promise.resolve(); - } -} - -class MockAuthService implements Partial { - coreLogout() { - return Promise.resolve(); - } -} - -class MockAuthStorageService implements Partial { - getToken() { - return of({ access_token: 'acc_token' } as AuthToken); - } -} - -class MockOAuthLibWrapperService implements Partial {} - -class MockRoutingService implements Partial { - go() {} -} - -class MockGlobalMessageService implements Partial { - add() {} -} - -class MockOccEndpointsService implements Partial { - getBaseEndpoint() { - return 'some-server/occ'; - } -} - -describe('AsmAuthHttpHeaderService', () => { - let service: AsmAuthHttpHeaderService; - let authService: AuthService; - let routingService: RoutingService; - let csAgentAuthService: CsAgentAuthService; - let globalMessageService: GlobalMessageService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - AsmAuthHttpHeaderService, - { provide: CsAgentAuthService, useClass: MockCsAgentAuthService }, - { provide: AuthService, useClass: MockAuthService }, - { - provide: OAuthLibWrapperService, - useClass: MockOAuthLibWrapperService, - }, - { provide: RoutingService, useClass: MockRoutingService }, - { provide: GlobalMessageService, useClass: MockGlobalMessageService }, - { provide: OccEndpointsService, useClass: MockOccEndpointsService }, - { provide: AuthStorageService, useClass: MockAuthStorageService }, - ], - }); - - service = TestBed.inject(AsmAuthHttpHeaderService); - authService = TestBed.inject(AuthService); - routingService = TestBed.inject(RoutingService); - csAgentAuthService = TestBed.inject(CsAgentAuthService); - globalMessageService = TestBed.inject(GlobalMessageService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('shouldCatchError', () => { - it('should return true for occ calls', () => { - expect( - service.shouldCatchError(new HttpRequest('GET', 'some-server/occ/cart')) - ).toBeTrue(); - }); - - it('should return true for cs agent requests', () => { - expect( - service.shouldCatchError( - new HttpRequest('GET', 'some-server/csagent', { - headers: new HttpHeaders({ 'cx-use-csagent-token': 'true' }), - }) - ) - ).toBeTrue(); - }); - - it('should return false for any other requests', () => { - expect( - service.shouldCatchError(new HttpRequest('GET', 'some-server/auth')) - ).toBeFalse(); - }); - }); - - describe('alterRequest', () => { - it('should add header for occ calls', () => { - const request = service.alterRequest( - new HttpRequest('GET', 'some-server/occ/cart') - ); - expect(request.headers.get('Authorization')).toEqual('Bearer acc_token'); - }); - - it('should add header for cs agent calls', () => { - const request = service.alterRequest( - new HttpRequest('GET', 'some-server/csagent', { - headers: new HttpHeaders({ 'cx-use-csagent-token': 'true' }), - }) - ); - expect(request.headers.get('Authorization')).toEqual('Bearer acc_token'); - }); - - it('should remove cs agent header from requests', () => { - const request = service.alterRequest( - new HttpRequest('GET', 'some-server/csagent', { - headers: new HttpHeaders({ 'cx-use-csagent-token': 'true' }), - }) - ); - expect(request.headers.has('cx-use-csagent-token')).toBe(false); - }); - - it('should not do anything for other requests', () => { - const request = service.alterRequest( - new HttpRequest('GET', 'some-server/non-occ/cart') - ); - expect(request.headers.has('Authorization')).toBe(false); - }); - }); - - describe('handleExpiredRefreshToken', () => { - it('should work the same as in AuthHeaderService when there is normally logged user', () => { - spyOn(authService, 'coreLogout').and.callThrough(); - spyOn(routingService, 'go').and.callThrough(); - - service.handleExpiredRefreshToken(); - - expect(authService.coreLogout).toHaveBeenCalled(); - expect(routingService.go).toHaveBeenCalledWith({ cxRoute: 'login' }); - }); - - it('should logoutCustomerSupportAgent when cs agent is logged in', () => { - spyOn(authService, 'coreLogout').and.callThrough(); - spyOn( - csAgentAuthService, - 'isCustomerSupportAgentLoggedIn' - ).and.returnValue(of(true)); - spyOn(csAgentAuthService, 'logoutCustomerSupportAgent').and.callThrough(); - spyOn(globalMessageService, 'add').and.callThrough(); - - service.handleExpiredRefreshToken(); - - expect(authService.coreLogout).not.toHaveBeenCalled(); - expect(csAgentAuthService.logoutCustomerSupportAgent).toHaveBeenCalled(); - expect(globalMessageService.add).toHaveBeenCalledWith( - { - key: 'asm.csagentTokenExpired', - }, - GlobalMessageType.MSG_TYPE_ERROR - ); - }); - }); -}); diff --git a/projects/core/src/asm/services/asm-auth-http-header.service.ts b/projects/core/src/asm/services/asm-auth-http-header.service.ts deleted file mode 100644 index d1d3af484f1..00000000000 --- a/projects/core/src/asm/services/asm-auth-http-header.service.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { HttpRequest } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { take } from 'rxjs/operators'; -import { AuthService } from '../../auth/user-auth/facade/auth.service'; -import { AuthHttpHeaderService } from '../../auth/user-auth/services/auth-http-header.service'; -import { AuthStorageService } from '../../auth/user-auth/services/auth-storage.service'; -import { OAuthLibWrapperService } from '../../auth/user-auth/services/oauth-lib-wrapper.service'; -import { GlobalMessageService } from '../../global-message/facade/global-message.service'; -import { GlobalMessageType } from '../../global-message/models/global-message.model'; -import { OccEndpointsService } from '../../occ/services/occ-endpoints.service'; -import { - InterceptorUtil, - USE_CUSTOMER_SUPPORT_AGENT_TOKEN, -} from '../../occ/utils/interceptor-util'; -import { RoutingService } from '../../routing/facade/routing.service'; -import { CsAgentAuthService } from '../facade/csagent-auth.service'; - -/** - * @deprecated since 3.2, use asm lib instead - * - * Overrides `AuthHttpHeaderService` to handle asm calls as well (not only OCC) - * in cases of normal user session and on customer emulation. - */ -@Injectable({ - providedIn: 'root', -}) -export class AsmAuthHttpHeaderService extends AuthHttpHeaderService { - constructor( - protected authService: AuthService, - protected authStorageService: AuthStorageService, - protected csAgentAuthService: CsAgentAuthService, - protected oAuthLibWrapperService: OAuthLibWrapperService, - protected routingService: RoutingService, - protected globalMessageService: GlobalMessageService, - protected occEndpointsService: OccEndpointsService - ) { - super( - authService, - authStorageService, - oAuthLibWrapperService, - routingService, - occEndpointsService, - globalMessageService - ); - } - - /** - * @override - * - * Checks if particular request should be handled by this service. - */ - public shouldCatchError(request: HttpRequest): boolean { - return ( - super.shouldCatchError(request) || this.isCSAgentTokenRequest(request) - ); - } - - /** - * @override - * - * Adds `Authorization` header to occ and CS agent requests. - * For CS agent requests also removes the `cx-use-csagent-token` header (to avoid problems with CORS). - */ - public alterRequest(request: HttpRequest): HttpRequest { - const hasAuthorizationHeader = !!this.getAuthorizationHeader(request); - const isCSAgentRequest = this.isCSAgentTokenRequest(request); - - let req = super.alterRequest(request); - - if (!hasAuthorizationHeader && isCSAgentRequest) { - req = request.clone({ - setHeaders: { - ...this.createAuthorizationHeader(), - }, - }); - return InterceptorUtil.removeHeader( - USE_CUSTOMER_SUPPORT_AGENT_TOKEN, - req - ); - } - return req; - } - - protected isCSAgentTokenRequest(request: HttpRequest): boolean { - const isRequestWithCSAgentToken = InterceptorUtil.getInterceptorParam( - USE_CUSTOMER_SUPPORT_AGENT_TOKEN, - request.headers - ); - return Boolean(isRequestWithCSAgentToken); - } - - /** - * @override - * - * On backend errors indicating expired `refresh_token` we need to logout - * currently logged in user and CS agent. - */ - public handleExpiredRefreshToken(): void { - this.csAgentAuthService - .isCustomerSupportAgentLoggedIn() - .pipe(take(1)) - .subscribe((csAgentLoggedIn) => { - if (csAgentLoggedIn) { - this.csAgentAuthService.logoutCustomerSupportAgent(); - this.globalMessageService.add( - { - key: 'asm.csagentTokenExpired', - }, - GlobalMessageType.MSG_TYPE_ERROR - ); - } else { - super.handleExpiredRefreshToken(); - } - }); - } -} diff --git a/projects/core/src/asm/services/asm-auth-storage.service.spec.ts b/projects/core/src/asm/services/asm-auth-storage.service.spec.ts deleted file mode 100644 index b4e4a2bf551..00000000000 --- a/projects/core/src/asm/services/asm-auth-storage.service.spec.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { take } from 'rxjs/operators'; -import { AuthToken } from '../../auth/index'; -import { AsmAuthStorageService, TokenTarget } from './asm-auth-storage.service'; - -describe('AsmAuthStorageService', () => { - let service: AsmAuthStorageService; - - const authToken: AuthToken = { - access_token: 'accessToken', - refresh_token: 'refreshToken', - expires_at: 'expiresAt', - granted_scopes: ['scope1', 'scope2'], - access_token_stored_at: 'storedAt', - }; - - beforeEach(() => { - service = new AsmAuthStorageService(); - service.setTokenTarget(TokenTarget.User); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('getTokenTarget()', () => { - it('should return token target', (done: DoneFn) => { - service - .getTokenTarget() - .pipe(take(1)) - .subscribe((tokenTarget) => { - expect(tokenTarget).toEqual(TokenTarget.User); - - done(); - }); - }); - }); - - describe('getEmulatedUserToken()', () => { - it('should return undefined without token set', () => { - const token: AuthToken = service.getEmulatedUserToken(); - - expect(token).toBeUndefined(); - }); - - it('should return emulated user token', () => { - service.setEmulatedUserToken(authToken); - - const token: AuthToken = service.getEmulatedUserToken(); - - expect(token).toEqual(authToken); - }); - }); - - describe('setEmulatedUserToken()', () => { - it('should set emulated user token', () => { - service.setEmulatedUserToken(authToken); - - const token: AuthToken = service.getEmulatedUserToken(); - - expect(token).toEqual(authToken); - }); - }); - - describe('setTokenTarget()', () => { - it('should set token target', (done: DoneFn) => { - service.setTokenTarget(TokenTarget.CSAgent); - - service - .getTokenTarget() - .pipe(take(1)) - .subscribe((tokenTarget) => { - expect(tokenTarget).toEqual(TokenTarget.CSAgent); - - done(); - }); - }); - }); - - describe('switchTokenTargetToCSAgent()', () => { - it('should change target to CSAgent', (done: DoneFn) => { - service.switchTokenTargetToCSAgent(); - - service - .getTokenTarget() - .pipe(take(1)) - .subscribe((tokenTarget) => { - expect(tokenTarget).toEqual(TokenTarget.CSAgent); - - done(); - }); - }); - }); - - describe('switchTokenTargetToUser()', () => { - it('should change target to User', (done: DoneFn) => { - service.switchTokenTargetToCSAgent(); - service.switchTokenTargetToUser(); - - service - .getTokenTarget() - .pipe(take(1)) - .subscribe((tokenTarget) => { - expect(tokenTarget).toEqual(TokenTarget.User); - - done(); - }); - }); - }); - - describe('clearEmulatedUserToken()', () => { - it('should clear emulated user token', () => { - service.clearEmulatedUserToken(); - - const token: AuthToken = service.getEmulatedUserToken(); - - expect(token).toBeUndefined(); - }); - }); -}); diff --git a/projects/core/src/asm/services/asm-auth-storage.service.ts b/projects/core/src/asm/services/asm-auth-storage.service.ts deleted file mode 100644 index a0afde23248..00000000000 --- a/projects/core/src/asm/services/asm-auth-storage.service.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { Injectable } from '@angular/core'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { AuthToken } from '../../auth/user-auth/models/auth-token.model'; -import { AuthStorageService } from '../../auth/user-auth/services/auth-storage.service'; - -/** - * @deprecated since 3.2, use asm lib instead - * - * Indicates if auth token is for regular user or CS Agent. - */ -export enum TokenTarget { - CSAgent = 'CSAgent', - User = 'User', -} - -/** - * @deprecated since 3.2, use asm lib instead - * - * With AsmAuthStorageService apart from storing the token we also need to store - * information for which user is the token (regular user or CS Agent). - * - * Overrides `AuthStorageService`. - */ -@Injectable({ - providedIn: 'root', -}) -export class AsmAuthStorageService extends AuthStorageService { - protected _tokenTarget$: Observable = new BehaviorSubject( - TokenTarget.User - ); - - /** - * When CS Agent logs in during regular user session we store the regular - * user token to restore the session after CS Agent logout. - * - * This supports in-store use case when CS Agent want's to quickly help - * customer and then give an option to customer to continue the process. - */ - protected emulatedUserToken: AuthToken; - - /** - * Get target user for current auth token. - * - * @return observable with TokenTarget - */ - getTokenTarget(): Observable { - return this._tokenTarget$; - } - - /** - * Set new token target. - * - * @param tokenTarget - */ - setTokenTarget(tokenTarget: TokenTarget): void { - (this._tokenTarget$ as BehaviorSubject).next(tokenTarget); - } - - /** - * Get token for previously user session, when it was interrupted by CS agent login. - * - * @return previously logged in user token. - */ - getEmulatedUserToken(): AuthToken { - return this.emulatedUserToken; - } - - /** - * Save user token on CS agent login. - * - * @param token - */ - setEmulatedUserToken(token: AuthToken): void { - this.emulatedUserToken = token; - } - - /** - * Change token target to CS Agent. - */ - switchTokenTargetToCSAgent(): void { - (this._tokenTarget$ as BehaviorSubject).next( - TokenTarget.CSAgent - ); - } - - /** - * Change token target to user. - */ - switchTokenTargetToUser(): void { - (this._tokenTarget$ as BehaviorSubject).next(TokenTarget.User); - } - - /** - * When we start emulation from the UI (not by ASM login) we can't restore user session on cs agent logout. - * Only available solution is to drop session we could restore, to avoid account hijack. - */ - clearEmulatedUserToken(): void { - this.emulatedUserToken = undefined; - } -} diff --git a/projects/core/src/asm/services/asm-auth.service.spec.ts b/projects/core/src/asm/services/asm-auth.service.spec.ts deleted file mode 100644 index 280c33954dc..00000000000 --- a/projects/core/src/asm/services/asm-auth.service.spec.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { inject, TestBed } from '@angular/core/testing'; -import { Store, StoreModule } from '@ngrx/store'; -import { BehaviorSubject } from 'rxjs'; -import { take } from 'rxjs/operators'; -import { - AuthRedirectService, - AuthToken, - OAuthLibWrapperService, - StateWithClientAuth, - UserIdService, -} from '../../auth/index'; -import { GlobalMessageService } from '../../global-message/index'; -import { PROCESS_FEATURE } from '../../process/index'; -import { getReducers as getProcessReducers } from '../../process/store/reducers/index'; -import { RoutingService } from '../../routing/index'; -import { ASM_FEATURE, getReducers as getAsmReducers } from '../store/index'; -import { AsmAuthStorageService, TokenTarget } from './asm-auth-storage.service'; -import { AsmAuthService } from './asm-auth.service'; - -const authToken: AuthToken = { - access_token: 'test_access_token', - refresh_token: 'test_refresh_token', - expires_at: 'test_expires', - granted_scopes: ['scope1', 'scope2'], - access_token_stored_at: 'test_token_stored_at', -}; -const loginInfo = { - userId: 'testUser', - password: 'password123', -}; - -let isEmulated$: BehaviorSubject; -let tokenTarget$: BehaviorSubject; -let authToken$: BehaviorSubject; - -class MockUserIdService { - clearUserId = jasmine.createSpy(); - setUserId = jasmine.createSpy(); - - isEmulated = () => isEmulated$.asObservable(); -} - -class MockOAuthLibWrapperService { - revokeAndLogout = jasmine.createSpy().and.returnValue(Promise.resolve()); - initLoginFlow = jasmine.createSpy(); - - authorizeWithPasswordFlow = () => new Promise(() => {}); -} - -class MockAsmAuthStorageService { - clearEmulatedUserToken = jasmine.createSpy(); - - getToken = () => authToken$.asObservable(); - getTokenTarget = () => tokenTarget$.asObservable(); -} - -class MockGlobalMessageService { - add = jasmine.createSpy(); -} - -class MockAuthRedirectService {} -class MockRoutingService {} - -describe('AsmAuthService', () => { - let service: AsmAuthService; - let store: Store; - let userIdService: UserIdService; - let oAuthLibWrapperService: OAuthLibWrapperService; - let asmAuthStorageService: AsmAuthStorageService; - let globalMessageService: GlobalMessageService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({}), - StoreModule.forFeature(ASM_FEATURE, getAsmReducers()), - StoreModule.forFeature(PROCESS_FEATURE, getProcessReducers()), - ], - providers: [ - AsmAuthService, - { provide: UserIdService, useClass: MockUserIdService }, - { - provide: OAuthLibWrapperService, - useClass: MockOAuthLibWrapperService, - }, - { provide: AsmAuthStorageService, useClass: MockAsmAuthStorageService }, - { - provide: AuthRedirectService, - useClass: MockAuthRedirectService, - }, - { - provide: GlobalMessageService, - useClass: MockGlobalMessageService, - }, - { - provide: RoutingService, - useClass: MockRoutingService, - }, - ], - }); - - service = TestBed.inject(AsmAuthService); - store = TestBed.inject(Store); - userIdService = TestBed.inject(UserIdService); - oAuthLibWrapperService = TestBed.inject(OAuthLibWrapperService); - asmAuthStorageService = TestBed.inject(AsmAuthStorageService); - globalMessageService = TestBed.inject(GlobalMessageService); - - spyOn(store, 'dispatch').and.callThrough(); - }); - - beforeEach(() => { - isEmulated$ = new BehaviorSubject(false); - tokenTarget$ = new BehaviorSubject(TokenTarget.User); - authToken$ = new BehaviorSubject(authToken); - }); - - it('should be injected', inject( - [AsmAuthService], - (asmAuthService: AsmAuthService) => { - expect(asmAuthService).toBeTruthy(); - } - )); - - describe('loginWithCredentials()', () => { - it('should authorize if user can login', () => { - spyOn( - oAuthLibWrapperService, - 'authorizeWithPasswordFlow' - ).and.callThrough(); - service.loginWithCredentials(loginInfo.userId, loginInfo.password); - - expect( - oAuthLibWrapperService.authorizeWithPasswordFlow - ).toHaveBeenCalledWith(loginInfo.userId, loginInfo.password); - }); - - it('should warn about CS Agent if user cannot login', () => { - tokenTarget$.next(TokenTarget.CSAgent); - - service.loginWithCredentials(loginInfo.userId, loginInfo.password); - - expect(globalMessageService.add).toHaveBeenCalled(); - }); - }); - - describe('loginWithRedirect()', () => { - it('should login and redirect if user can login', () => { - const result = service.loginWithRedirect(); - - expect(result).toBeTrue(); - expect(oAuthLibWrapperService.initLoginFlow).toHaveBeenCalled(); - }); - - it('should warn about CS Agent if user cannot login', () => { - tokenTarget$.next(TokenTarget.CSAgent); - - const result = service.loginWithRedirect(); - - expect(result).toBeFalse(); - expect(globalMessageService.add).toHaveBeenCalled(); - }); - }); - - describe('coreLogout()', () => { - it('should logout when user not emulated', () => { - service.coreLogout(); - - expect(userIdService.clearUserId).toHaveBeenCalled(); - expect(oAuthLibWrapperService.revokeAndLogout).toHaveBeenCalled(); - }); - - it('should logout when emulating user', (done: DoneFn) => { - isEmulated$.next(true); - - service.coreLogout().then(() => { - expect(asmAuthStorageService.clearEmulatedUserToken).toHaveBeenCalled(); - expect(userIdService.clearUserId).toHaveBeenCalled(); - expect(store.dispatch).toHaveBeenCalled(); - - done(); - }); - }); - }); - - describe('isUserLoggedIn()', () => { - describe('without access_token', () => { - it('should return false', (done: DoneFn) => { - const newToken = { ...authToken }; - delete newToken['access_token']; - - authToken$ = new BehaviorSubject(newToken); - - service - .isUserLoggedIn() - .pipe(take(1)) - .subscribe((isLoggedIn: boolean) => { - expect(isLoggedIn).toBeFalse(); - - done(); - }); - }); - }); - - describe('with access_token', () => { - it('should return true for users', (done: DoneFn) => { - service - .isUserLoggedIn() - .pipe(take(1)) - .subscribe((isLoggedIn: boolean) => { - expect(isLoggedIn).toBeTrue(); - - done(); - }); - }); - - it('should return true for CSAgents emulating user', (done: DoneFn) => { - tokenTarget$.next(TokenTarget.CSAgent); - isEmulated$.next(true); - - service - .isUserLoggedIn() - .pipe(take(1)) - .subscribe((isLoggedIn: boolean) => { - expect(isLoggedIn).toBeTrue(); - - done(); - }); - }); - - it('should return false for CSAgents not emulating user', (done: DoneFn) => { - tokenTarget$.next(TokenTarget.CSAgent); - - service - .isUserLoggedIn() - .pipe(take(1)) - .subscribe((isLoggedIn: boolean) => { - expect(isLoggedIn).toBeFalse(); - - done(); - }); - }); - }); - }); -}); diff --git a/projects/core/src/asm/services/asm-auth.service.ts b/projects/core/src/asm/services/asm-auth.service.ts deleted file mode 100644 index 45d402f69d4..00000000000 --- a/projects/core/src/asm/services/asm-auth.service.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { combineLatest, from, Observable, of } from 'rxjs'; -import { map, switchMap, take } from 'rxjs/operators'; -import { StateWithClientAuth } from '../../auth/client-auth/store/client-auth-state'; -import { AuthService } from '../../auth/user-auth/facade/auth.service'; -import { UserIdService } from '../../auth/user-auth/facade/user-id.service'; -import { AuthToken } from '../../auth/user-auth/models/auth-token.model'; -import { AuthRedirectService } from '../../auth/user-auth/services/auth-redirect.service'; -import { OAuthLibWrapperService } from '../../auth/user-auth/services/oauth-lib-wrapper.service'; -import { AuthActions } from '../../auth/user-auth/store/actions/index'; -import { - GlobalMessageService, - GlobalMessageType, -} from '../../global-message/index'; -import { RoutingService } from '../../routing/facade/routing.service'; -import { AsmAuthStorageService, TokenTarget } from './asm-auth-storage.service'; - -/** - * @deprecated since 3.2, use asm lib instead - * - * Version of AuthService that is working for both user na CS agent. - * Overrides AuthService when ASM module is enabled. - */ -@Injectable({ - providedIn: 'root', -}) -export class AsmAuthService extends AuthService { - constructor( - protected store: Store, - protected userIdService: UserIdService, - protected oAuthLibWrapperService: OAuthLibWrapperService, - protected authStorageService: AsmAuthStorageService, - protected authRedirectService: AuthRedirectService, - protected globalMessageService: GlobalMessageService, - protected routingService: RoutingService - ) { - super( - store, - userIdService, - oAuthLibWrapperService, - authStorageService, - authRedirectService, - routingService - ); - } - - protected canUserLogin(): boolean { - let tokenTarget: TokenTarget; - let token: AuthToken; - - this.authStorageService - .getToken() - .subscribe((tok) => (token = tok)) - .unsubscribe(); - this.authStorageService - .getTokenTarget() - .subscribe((tokTarget) => (tokenTarget = tokTarget)) - .unsubscribe(); - return !( - Boolean(token?.access_token) && tokenTarget === TokenTarget.CSAgent - ); - } - - protected warnAboutLoggedCSAgent(): void { - this.globalMessageService.add( - { - key: 'asm.auth.agentLoggedInError', - }, - GlobalMessageType.MSG_TYPE_ERROR - ); - } - - /** - * Loads a new user token with Resource Owner Password Flow when CS agent is not logged in. - * @param userId - * @param password - */ - async loginWithCredentials(userId: string, password: string): Promise { - if (this.canUserLogin()) { - await super.loginWithCredentials(userId, password); - } else { - this.warnAboutLoggedCSAgent(); - } - } - - /** - * Initialize Implicit/Authorization Code flow by redirecting to OAuth server when CS agent is not logged in. - */ - loginWithRedirect(): boolean { - if (this.canUserLogin()) { - super.loginWithRedirect(); - return true; - } else { - this.warnAboutLoggedCSAgent(); - return false; - } - } - - /** - * Revokes tokens and clears state for logged user (tokens, userId). - * To perform logout it is best to use `logout` method. Use this method with caution. - */ - coreLogout(): Promise { - return this.userIdService - .isEmulated() - .pipe( - take(1), - switchMap((isEmulated) => { - if (isEmulated) { - this.authStorageService.clearEmulatedUserToken(); - this.userIdService.clearUserId(); - this.store.dispatch(new AuthActions.Logout()); - return of(true); - } else { - return from(super.coreLogout()); - } - }) - ) - .toPromise(); - } - - /** - * Returns `true` if user is logged in or being emulated. - */ - isUserLoggedIn(): Observable { - return combineLatest([ - this.authStorageService.getToken(), - this.userIdService.isEmulated(), - this.authStorageService.getTokenTarget(), - ]).pipe( - map( - ([token, isEmulated, tokenTarget]) => - Boolean(token?.access_token) && - (tokenTarget === TokenTarget.User || - (tokenTarget === TokenTarget.CSAgent && isEmulated)) - ) - ); - } -} diff --git a/projects/core/src/asm/services/asm-state-persistence.service.spec.ts b/projects/core/src/asm/services/asm-state-persistence.service.spec.ts deleted file mode 100644 index 1bd626767d9..00000000000 --- a/projects/core/src/asm/services/asm-state-persistence.service.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { Store, StoreModule } from '@ngrx/store'; -import { of } from 'rxjs'; -import { take } from 'rxjs/operators'; -import { AuthToken } from '../../auth/user-auth/models/auth-token.model'; -import { StatePersistenceService } from '../../state/services/state-persistence.service'; -import { AsmActions, ASM_FEATURE, StateWithAsm } from '../store'; -import * as fromAsmReducers from '../store/reducers/index'; -import { AsmAuthStorageService, TokenTarget } from './asm-auth-storage.service'; -import { AsmStatePersistenceService } from './asm-state-persistence.service'; - -class MockAsmAuthStorageService implements Partial { - setEmulatedUserToken() {} - getEmulatedUserToken() { - return {} as AuthToken; - } - setTokenTarget() {} - getTokenTarget() { - return of(TokenTarget.CSAgent); - } -} - -describe('AsmStatePersistenceService', () => { - let service: AsmStatePersistenceService; - let persistenceService: StatePersistenceService; - let store: Store; - let asmAuthStorageService: AsmAuthStorageService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({}), - StoreModule.forFeature(ASM_FEATURE, fromAsmReducers.getReducers()), - ], - providers: [ - AsmStatePersistenceService, - StatePersistenceService, - { provide: AsmAuthStorageService, useClass: MockAsmAuthStorageService }, - ], - }); - - service = TestBed.inject(AsmStatePersistenceService); - persistenceService = TestBed.inject(StatePersistenceService); - store = TestBed.inject(Store); - asmAuthStorageService = TestBed.inject(AsmAuthStorageService); - spyOn(store, 'dispatch').and.stub(); - spyOn(persistenceService, 'syncWithStorage').and.stub(); - }); - - it('should inject service', () => { - expect(service).toBeTruthy(); - }); - - it('state should be updated after read from storage', () => { - spyOn(asmAuthStorageService, 'setEmulatedUserToken').and.callThrough(); - spyOn(asmAuthStorageService, 'setTokenTarget').and.callThrough(); - - service['onRead']({ - ui: { collapsed: true }, - emulatedUserToken: { - access_token: 'token', - access_token_stored_at: '1000', - }, - tokenTarget: TokenTarget.CSAgent, - }); - - expect(store.dispatch).toHaveBeenCalledTimes(1); - expect(store.dispatch).toHaveBeenCalledWith( - new AsmActions.AsmUiUpdate({ collapsed: true }) - ); - expect( - asmAuthStorageService.setEmulatedUserToken({ - access_token: 'token', - access_token_stored_at: '1000', - } as AuthToken) - ); - expect(asmAuthStorageService.setTokenTarget).toHaveBeenCalledWith( - TokenTarget.CSAgent - ); - }); - - it('should call persistenceService with correct attributes', () => { - const state$ = of(''); - spyOn(service as any, 'getAsmState').and.returnValue(state$); - - service.initSync(); - - expect(persistenceService.syncWithStorage).toHaveBeenCalledWith( - jasmine.objectContaining({ - key: 'asm', - state$, - }) - ); - expect(service['getAsmState']).toHaveBeenCalled(); - }); - - it('should return state from asm store', (done) => { - spyOn(asmAuthStorageService, 'getEmulatedUserToken').and.returnValue({ - access_token: 'token', - access_token_stored_at: '1000', - refresh_token: 'refresh_token', // this token should not be saved - }); - spyOn(asmAuthStorageService, 'getTokenTarget').and.returnValue( - of(TokenTarget.User) - ); - - service['getAsmState']() - .pipe(take(1)) - .subscribe((state) => { - expect(state).toEqual({ - ui: { collapsed: false }, - emulatedUserToken: { - access_token: 'token', - access_token_stored_at: '1000', - }, - tokenTarget: TokenTarget.User, - }); - done(); - }); - }); -}); diff --git a/projects/core/src/asm/services/asm-state-persistence.service.ts b/projects/core/src/asm/services/asm-state-persistence.service.ts deleted file mode 100644 index 0154955dd8a..00000000000 --- a/projects/core/src/asm/services/asm-state-persistence.service.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { Injectable, OnDestroy } from '@angular/core'; -import { select, Store } from '@ngrx/store'; -import { combineLatest, Observable, of, Subscription } from 'rxjs'; -import { map } from 'rxjs/operators'; -import { AuthToken } from '../../auth/user-auth/models/auth-token.model'; -import { StatePersistenceService } from '../../state/services/state-persistence.service'; -import { AsmUi } from '../models/asm.models'; -import { AsmActions, AsmSelectors, StateWithAsm } from '../store'; -import { AsmAuthStorageService, TokenTarget } from './asm-auth-storage.service'; - -/** - * @deprecated since 3.2, use asm lib instead - * - * ASM state synced to browser storage. - */ -export interface SyncedAsmState { - ui?: AsmUi; - emulatedUserToken?: AuthToken; - tokenTarget?: TokenTarget; -} - -/** - * @deprecated since 3.2, use asm lib instead - * - * Responsible for storing ASM state in the browser storage. - * Uses `StatePersistenceService` mechanism. - */ -@Injectable({ - providedIn: 'root', -}) -export class AsmStatePersistenceService implements OnDestroy { - protected subscription = new Subscription(); - - constructor( - protected statePersistenceService: StatePersistenceService, - protected store: Store, - protected authStorageService: AsmAuthStorageService - ) {} - - /** - * Identifier used for storage key. - */ - protected key = 'asm'; - - /** - * Initializes the synchronization between state and browser storage. - */ - public initSync() { - this.subscription.add( - this.statePersistenceService.syncWithStorage({ - key: this.key, - state$: this.getAsmState(), - onRead: (state) => this.onRead(state), - }) - ); - } - - /** - * Gets and transforms state from different sources into the form that should - * be saved in storage. - */ - protected getAsmState(): Observable { - return combineLatest([ - this.store.pipe(select(AsmSelectors.getAsmUi)), - of(this.authStorageService.getEmulatedUserToken()), - this.authStorageService.getTokenTarget(), - ]).pipe( - map(([ui, emulatedUserToken, tokenTarget]) => { - let emulatedToken = emulatedUserToken; - if (emulatedToken) { - emulatedToken = { ...emulatedUserToken }; - // To minimize risk of user account hijacking we don't persist emulated user refresh_token - delete emulatedToken.refresh_token; - } - return { - ui, - emulatedUserToken: emulatedToken, - tokenTarget, - }; - }) - ); - } - - /** - * Function called on each browser storage read. - * Used to update state from browser -> state. - */ - protected onRead(state: SyncedAsmState) { - if (state) { - if (state.ui) { - this.store.dispatch(new AsmActions.AsmUiUpdate(state.ui)); - } - if (state.emulatedUserToken) { - this.authStorageService.setEmulatedUserToken(state.emulatedUserToken); - } - if (state.tokenTarget) { - this.authStorageService.setTokenTarget(state.tokenTarget); - } - } - } - - ngOnDestroy(): void { - this.subscription.unsubscribe(); - } -} diff --git a/projects/core/src/asm/services/index.ts b/projects/core/src/asm/services/index.ts deleted file mode 100644 index c48be9b78c3..00000000000 --- a/projects/core/src/asm/services/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './asm-auth-http-header.service'; -export * from './asm-auth-storage.service'; -export * from './asm-auth.service'; -export * from './asm-state-persistence.service'; diff --git a/projects/core/src/asm/store/actions/asm-ui.action.ts b/projects/core/src/asm/store/actions/asm-ui.action.ts deleted file mode 100644 index 80e702b23b3..00000000000 --- a/projects/core/src/asm/store/actions/asm-ui.action.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Action } from '@ngrx/store'; -import { AsmUi } from '../../models/asm.models'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const ASM_UI_UPDATE = '[Asm] UI Update'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export class AsmUiUpdate implements Action { - readonly type = ASM_UI_UPDATE; - constructor(public payload: AsmUi) {} -} - -/** - * @deprecated since 3.2, use asm lib instead - */ -// action types -export type AsmUiAction = AsmUiUpdate; diff --git a/projects/core/src/asm/store/actions/customer-group.actions.ts b/projects/core/src/asm/store/actions/customer-group.actions.ts deleted file mode 100644 index 7028022bc4f..00000000000 --- a/projects/core/src/asm/store/actions/customer-group.actions.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './asm-ui.action'; -export * from './customer.action'; -export * from './logout-agent.action'; diff --git a/projects/core/src/asm/store/actions/customer.action.spec.ts b/projects/core/src/asm/store/actions/customer.action.spec.ts deleted file mode 100644 index 70fe2b96c61..00000000000 --- a/projects/core/src/asm/store/actions/customer.action.spec.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { User } from '../../../model/misc.model'; -import { StateUtils } from '../../../state/utils/index'; -import { - CustomerSearchOptions, - CustomerSearchPage, -} from '../../models/asm.models'; -import { CUSTOMER_SEARCH_DATA } from '../asm-state'; -import { AsmActions } from './index'; - -const mockUser: User = { - displayUid: 'Display Uid', - firstName: 'First', - lastName: 'Last', - name: 'First Last', - uid: 'user@test.com', - customerId: '123456', -}; - -const mockCustomerSearchPage: CustomerSearchPage = { - entries: [mockUser], -} as CustomerSearchPage; - -describe('Customer Actions', () => { - describe('Customer Search Actions', () => { - it('should create the Customer Search Actions', () => { - const searchOptions: CustomerSearchOptions = { query: 'abc' }; - const action = new AsmActions.CustomerSearch(searchOptions); - expect({ ...action }).toEqual({ - type: AsmActions.CUSTOMER_SEARCH, - meta: StateUtils.loadMeta(CUSTOMER_SEARCH_DATA), - payload: searchOptions, - }); - }); - - it('should create the CustomerSearchFail action', () => { - const error = 'anError'; - const action = new AsmActions.CustomerSearchFail(error); - - expect({ ...action }).toEqual({ - type: AsmActions.CUSTOMER_SEARCH_FAIL, - meta: StateUtils.failMeta(CUSTOMER_SEARCH_DATA), - payload: error, - }); - }); - - it('should create the CustomerSearchSuccess action', () => { - const action = new AsmActions.CustomerSearchSuccess( - mockCustomerSearchPage - ); - - expect({ ...action }).toEqual({ - type: AsmActions.CUSTOMER_SEARCH_SUCCESS, - meta: StateUtils.successMeta(CUSTOMER_SEARCH_DATA), - payload: mockCustomerSearchPage, - }); - }); - - it('should create the CustomerSearchReset action', () => { - const action = new AsmActions.CustomerSearchReset(); - - expect({ ...action }).toEqual({ - type: AsmActions.CUSTOMER_SEARCH_RESET, - meta: StateUtils.resetMeta(CUSTOMER_SEARCH_DATA), - }); - }); - }); -}); diff --git a/projects/core/src/asm/store/actions/customer.action.ts b/projects/core/src/asm/store/actions/customer.action.ts deleted file mode 100644 index c9ebea08de8..00000000000 --- a/projects/core/src/asm/store/actions/customer.action.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { StateUtils } from '../../../state/utils/index'; -import { - CustomerSearchOptions, - CustomerSearchPage, -} from '../../models/asm.models'; -import { CUSTOMER_SEARCH_DATA } from '../asm-state'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const CUSTOMER_SEARCH = '[Asm] Customer Search'; -/** - * @deprecated since 3.2, use asm lib instead - */ -export const CUSTOMER_SEARCH_FAIL = '[Asm] Customer Search Fail'; -/** - * @deprecated since 3.2, use asm lib instead - */ -export const CUSTOMER_SEARCH_SUCCESS = '[Asm] Customer Search Success'; -/** - * @deprecated since 3.2, use asm lib instead - */ -export const CUSTOMER_SEARCH_RESET = '[Asm] Customer Search Reset'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export class CustomerSearch extends StateUtils.LoaderLoadAction { - readonly type = CUSTOMER_SEARCH; - constructor(public payload: CustomerSearchOptions) { - super(CUSTOMER_SEARCH_DATA); - } -} - -/** - * @deprecated since 3.2, use asm lib instead - */ -export class CustomerSearchFail extends StateUtils.LoaderFailAction { - readonly type = CUSTOMER_SEARCH_FAIL; - constructor(public payload: any) { - super(CUSTOMER_SEARCH_DATA); - } -} - -/** - * @deprecated since 3.2, use asm lib instead - */ -export class CustomerSearchSuccess extends StateUtils.LoaderSuccessAction { - readonly type = CUSTOMER_SEARCH_SUCCESS; - constructor(public payload: CustomerSearchPage) { - super(CUSTOMER_SEARCH_DATA); - } -} - -/** - * @deprecated since 3.2, use asm lib instead - */ -export class CustomerSearchReset extends StateUtils.LoaderResetAction { - readonly type = CUSTOMER_SEARCH_RESET; - constructor() { - super(CUSTOMER_SEARCH_DATA); - } -} - -/** - * @deprecated since 3.2, use asm lib instead - */ -// action types -export type CustomerAction = - | CustomerSearch - | CustomerSearchFail - | CustomerSearchSuccess - | CustomerSearchReset; diff --git a/projects/core/src/asm/store/actions/index.ts b/projects/core/src/asm/store/actions/index.ts deleted file mode 100644 index 86c61a40ec2..00000000000 --- a/projects/core/src/asm/store/actions/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import * as AsmActions from './customer-group.actions'; -export { AsmActions }; diff --git a/projects/core/src/asm/store/actions/logout-agent.action.ts b/projects/core/src/asm/store/actions/logout-agent.action.ts deleted file mode 100644 index 26e6f872650..00000000000 --- a/projects/core/src/asm/store/actions/logout-agent.action.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Action } from '@ngrx/store'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const LOGOUT_CUSTOMER_SUPPORT_AGENT = - '[Auth] Logout Customer Support Agent'; - -/** - * @deprecated since 3.2, use asm lib instead - * - * Action dispatched after customer support agent logout. Used to clear store data (ui, search results) - */ -export class LogoutCustomerSupportAgent implements Action { - readonly type = LOGOUT_CUSTOMER_SUPPORT_AGENT; -} diff --git a/projects/core/src/asm/store/asm-state.ts b/projects/core/src/asm/store/asm-state.ts deleted file mode 100644 index 47d168309ab..00000000000 --- a/projects/core/src/asm/store/asm-state.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { LoaderState } from '../../state/utils/loader/loader-state'; -import { AsmUi, CustomerSearchPage } from '../models/asm.models'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const ASM_FEATURE = 'asm'; -/** - * @deprecated since 3.2, use asm lib instead - */ -export const CUSTOMER_SEARCH_DATA = '[asm] Customer search data'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export interface StateWithAsm { - [ASM_FEATURE]: AsmState; -} - -/** - * @deprecated since 3.2, use asm lib instead - */ -export interface AsmState { - customerSearchResult: LoaderState; - asmUi: AsmUi; -} diff --git a/projects/core/src/asm/store/asm-store.module.ts b/projects/core/src/asm/store/asm-store.module.ts deleted file mode 100644 index 06aeb39080d..00000000000 --- a/projects/core/src/asm/store/asm-store.module.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { EffectsModule } from '@ngrx/effects'; -import { StoreModule } from '@ngrx/store'; -import { StateModule } from '../../state/state.module'; -import { ASM_FEATURE } from './asm-state'; -import { effects } from './effects/index'; -import { metaReducers, reducerProvider, reducerToken } from './reducers/index'; - -@NgModule({ - imports: [ - CommonModule, - StateModule, - StoreModule.forFeature(ASM_FEATURE, reducerToken, { metaReducers }), - EffectsModule.forFeature(effects), - ], - providers: [reducerProvider], -}) -export class AsmStoreModule {} diff --git a/projects/core/src/asm/store/effects/customer.effect.spec.ts b/projects/core/src/asm/store/effects/customer.effect.spec.ts deleted file mode 100644 index 69246684a68..00000000000 --- a/projects/core/src/asm/store/effects/customer.effect.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { provideMockActions } from '@ngrx/effects/testing'; -import { cold, hot } from 'jasmine-marbles'; -import { Observable, of } from 'rxjs'; -import { AsmConnector } from '../../connectors/asm.connector'; -import { CustomerSearchPage } from '../../models/asm.models'; -import { AsmActions } from '../actions/index'; -import { CustomerEffects } from './customer.effect'; - -class AsmConnectorMock { - customerSearch(_searchTerm: string): Observable { - return of({}); - } -} - -describe('Customer effect', () => { - let asmConnector: AsmConnector; - let customerEffects: CustomerEffects; - let actions$: Observable; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - CustomerEffects, - { - provide: AsmConnector, - useClass: AsmConnectorMock, - }, - provideMockActions(() => actions$), - ], - }); - - customerEffects = TestBed.inject(CustomerEffects); - asmConnector = TestBed.inject(AsmConnector); - - spyOn(asmConnector, 'customerSearch').and.returnValue(of({ entries: [] })); - }); - - describe('customerSearch$', () => { - it('should provide search results', () => { - const action = new AsmActions.CustomerSearch({ query: 'abc' }); - const completion = new AsmActions.CustomerSearchSuccess({ - entries: [], - } as CustomerSearchPage); - - actions$ = hot('-a', { a: action }); - const expected = cold('-b', { b: completion }); - - expect(customerEffects.customerSearch$).toBeObservable(expected); - }); - }); -}); diff --git a/projects/core/src/asm/store/effects/customer.effect.ts b/projects/core/src/asm/store/effects/customer.effect.ts deleted file mode 100644 index 3c4ad437a98..00000000000 --- a/projects/core/src/asm/store/effects/customer.effect.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, Effect, ofType } from '@ngrx/effects'; -import { Observable, of } from 'rxjs'; -import { catchError, map, switchMap } from 'rxjs/operators'; -import { normalizeHttpError } from '../../../util/normalize-http-error'; -import { AsmConnector } from '../../connectors/asm.connector'; -import { CustomerSearchPage } from '../../models/asm.models'; -import { AsmActions } from '../actions/index'; - -@Injectable() -export class CustomerEffects { - @Effect() - customerSearch$: Observable = this.actions$.pipe( - ofType(AsmActions.CUSTOMER_SEARCH), - map((action: AsmActions.CustomerSearch) => action.payload), - switchMap((options) => - this.asmConnector.customerSearch(options).pipe( - map((customerSearchResults: CustomerSearchPage) => { - return new AsmActions.CustomerSearchSuccess(customerSearchResults); - }), - catchError((error) => - of(new AsmActions.CustomerSearchFail(normalizeHttpError(error))) - ) - ) - ) - ); - - constructor(private actions$: Actions, private asmConnector: AsmConnector) {} -} diff --git a/projects/core/src/asm/store/effects/index.ts b/projects/core/src/asm/store/effects/index.ts deleted file mode 100644 index da646fa5653..00000000000 --- a/projects/core/src/asm/store/effects/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { CustomerEffects } from './customer.effect'; - -export const effects: any[] = [CustomerEffects]; - -export * from './customer.effect'; diff --git a/projects/core/src/asm/store/index.ts b/projects/core/src/asm/store/index.ts deleted file mode 100644 index 4ead492a260..00000000000 --- a/projects/core/src/asm/store/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './actions/index'; -export * from './asm-state'; -export * from './effects/index'; -export * from './reducers/index'; -export * from './selectors/index'; diff --git a/projects/core/src/asm/store/reducers/asm-ui.reducer.spec.ts b/projects/core/src/asm/store/reducers/asm-ui.reducer.spec.ts deleted file mode 100644 index 52d8fdd8380..00000000000 --- a/projects/core/src/asm/store/reducers/asm-ui.reducer.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { AsmUi } from '../../models/asm.models'; -import { AsmActions } from '../actions'; -import * as fromReducer from './asm-ui.reducer'; - -const mockAsmUiUpdated: AsmUi = { - collapsed: false, -}; - -describe('AsmUi reducer', () => { - it('should return the same state for undefined action', () => { - const { initialState } = fromReducer; - const action = {} as AsmActions.AsmUiAction; - const state = fromReducer.reducer(initialState, action); - - expect(state).toBe(initialState); - }); - - it('should return the initial state for undefined state', () => { - const { initialState } = fromReducer; - const action = {} as AsmActions.AsmUiAction; - const state = fromReducer.reducer(undefined, action); - - expect(state).toBe(initialState); - }); - - it('should update AsmUi', () => { - const { initialState } = fromReducer; - - expect(initialState).not.toBe(mockAsmUiUpdated); - const action = new AsmActions.AsmUiUpdate(mockAsmUiUpdated); - const state = fromReducer.reducer(initialState, action); - - expect(state).toEqual(mockAsmUiUpdated); - }); -}); diff --git a/projects/core/src/asm/store/reducers/asm-ui.reducer.ts b/projects/core/src/asm/store/reducers/asm-ui.reducer.ts deleted file mode 100644 index 73f2866607a..00000000000 --- a/projects/core/src/asm/store/reducers/asm-ui.reducer.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { AsmUi } from '../../models/asm.models'; -import { AsmActions } from '../actions/index'; - -export const initialState: AsmUi = { collapsed: false }; - -export function reducer( - state = initialState, - action: AsmActions.AsmUiAction -): AsmUi { - switch (action.type) { - case AsmActions.ASM_UI_UPDATE: { - return { - ...state, - ...action.payload, - }; - } - default: { - return state; - } - } -} diff --git a/projects/core/src/asm/store/reducers/index.ts b/projects/core/src/asm/store/reducers/index.ts deleted file mode 100644 index 24dfd562813..00000000000 --- a/projects/core/src/asm/store/reducers/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { InjectionToken, Provider } from '@angular/core'; -import { - Action, - ActionReducer, - ActionReducerMap, - MetaReducer, -} from '@ngrx/store'; -import { loaderReducer } from '../../../state/utils/loader/loader.reducer'; -import { CustomerSearchPage } from '../../models/asm.models'; -import { AsmActions } from '../actions'; -import { AsmState, CUSTOMER_SEARCH_DATA } from '../asm-state'; -import * as fromAsmUiReducer from './asm-ui.reducer'; - -export function getReducers(): ActionReducerMap { - return { - customerSearchResult: loaderReducer( - CUSTOMER_SEARCH_DATA - ), - asmUi: fromAsmUiReducer.reducer, - }; -} - -export const reducerToken: InjectionToken< - ActionReducerMap -> = new InjectionToken>('AsmReducers'); - -export const reducerProvider: Provider = { - provide: reducerToken, - useFactory: getReducers, -}; - -export function clearCustomerSupportAgentAsmState( - reducer: ActionReducer -): ActionReducer { - return function (state, action) { - if (action.type === AsmActions.LOGOUT_CUSTOMER_SUPPORT_AGENT) { - state = { - ...state, - customerSearchResult: undefined, - }; - } - return reducer(state, action); - }; -} - -export const metaReducers: MetaReducer[] = [ - clearCustomerSupportAgentAsmState, -]; diff --git a/projects/core/src/asm/store/selectors/asm-group.selectors.ts b/projects/core/src/asm/store/selectors/asm-group.selectors.ts deleted file mode 100644 index 33757c0b1c8..00000000000 --- a/projects/core/src/asm/store/selectors/asm-group.selectors.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './asm-ui.selectors'; -export * from './customer-search.selectors'; -export * from './feature.selector'; diff --git a/projects/core/src/asm/store/selectors/asm-ui.selectors.ts b/projects/core/src/asm/store/selectors/asm-ui.selectors.ts deleted file mode 100644 index aa08119c9f4..00000000000 --- a/projects/core/src/asm/store/selectors/asm-ui.selectors.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { createSelector, MemoizedSelector } from '@ngrx/store'; -import { AsmUi } from '../../models/asm.models'; -import { AsmState, StateWithAsm } from '../asm-state'; -import { getAsmState } from './feature.selector'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const getAsmUi: MemoizedSelector = createSelector( - getAsmState, - (state: AsmState) => state.asmUi -); diff --git a/projects/core/src/asm/store/selectors/customer-search.selectors.spec.ts b/projects/core/src/asm/store/selectors/customer-search.selectors.spec.ts deleted file mode 100644 index 726620622e3..00000000000 --- a/projects/core/src/asm/store/selectors/customer-search.selectors.spec.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { select, Store, StoreModule } from '@ngrx/store'; -import { User } from '../../../model/misc.model'; -import { LoaderState } from '../../../state/utils/loader/loader-state'; -import { CustomerSearchPage } from '../../models/asm.models'; -import { AsmActions } from '../actions'; -import { StateWithAsm } from '../asm-state'; -import * as fromReducers from '../reducers/index'; -import { AsmSelectors } from './index'; - -const mockUser: User = { - displayUid: 'Display Uid', - firstName: 'First', - lastName: 'Last', - name: 'First Last', - uid: 'user@test.com', - customerId: '123456', -}; - -const mockCustomerSearchPage: CustomerSearchPage = { - entries: [mockUser], -} as CustomerSearchPage; - -describe('Customer Search Results Selectors', () => { - let store: Store; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({}), - StoreModule.forFeature('asm', fromReducers.getReducers()), - ], - }); - - store = TestBed.inject(Store); - spyOn(store, 'dispatch').and.callThrough(); - }); - - it('should return a Customer Search results from the state', () => { - let result: CustomerSearchPage; - - store - .pipe(select(AsmSelectors.getCustomerSearchResults)) - .subscribe((value) => (result = value)); - expect(result).toEqual(undefined); - - store.dispatch( - new AsmActions.CustomerSearchSuccess(mockCustomerSearchPage) - ); - - expect(result).toEqual(mockCustomerSearchPage); - }); - - it('should return Customer Search results loading state from the state', () => { - let result: boolean; - - store - .pipe(select(AsmSelectors.getCustomerSearchResultsLoading)) - .subscribe((value) => (result = value)); - expect(result).toEqual(false); - - store.dispatch(new AsmActions.CustomerSearch({ query: 'abc' })); - - expect(result).toEqual(true); - }); - - it('should return Customer Search results loader state', () => { - store.dispatch( - new AsmActions.CustomerSearchSuccess(mockCustomerSearchPage) - ); - - let result: LoaderState; - store - .pipe(select(AsmSelectors.getCustomerSearchResultsLoaderState)) - .subscribe((value) => (result = value)) - .unsubscribe(); - - expect(result).toEqual({ - error: false, - loading: false, - success: true, - value: mockCustomerSearchPage, - } as LoaderState); - }); -}); diff --git a/projects/core/src/asm/store/selectors/customer-search.selectors.ts b/projects/core/src/asm/store/selectors/customer-search.selectors.ts deleted file mode 100644 index dfd99e962f6..00000000000 --- a/projects/core/src/asm/store/selectors/customer-search.selectors.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { createSelector, MemoizedSelector } from '@ngrx/store'; -import { StateUtils } from '../../../state/utils/index'; -import { CustomerSearchPage } from '../../models/asm.models'; -import { AsmState, StateWithAsm } from '../asm-state'; -import { getAsmState } from './feature.selector'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const getCustomerSearchResultsLoaderState: MemoizedSelector< - StateWithAsm, - StateUtils.LoaderState -> = createSelector( - getAsmState, - (state: AsmState) => state.customerSearchResult -); - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const getCustomerSearchResults: MemoizedSelector< - StateWithAsm, - CustomerSearchPage -> = createSelector(getCustomerSearchResultsLoaderState, (state) => - StateUtils.loaderValueSelector(state) -); - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const getCustomerSearchResultsLoading: MemoizedSelector< - StateWithAsm, - boolean -> = createSelector(getCustomerSearchResultsLoaderState, (state) => - StateUtils.loaderLoadingSelector(state) -); diff --git a/projects/core/src/asm/store/selectors/feature.selector.ts b/projects/core/src/asm/store/selectors/feature.selector.ts deleted file mode 100644 index 8cc89c73fd4..00000000000 --- a/projects/core/src/asm/store/selectors/feature.selector.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createFeatureSelector, MemoizedSelector } from '@ngrx/store'; -import { AsmState, ASM_FEATURE, StateWithAsm } from '../asm-state'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -export const getAsmState: MemoizedSelector< - StateWithAsm, - AsmState -> = createFeatureSelector(ASM_FEATURE); diff --git a/projects/core/src/asm/store/selectors/index.ts b/projects/core/src/asm/store/selectors/index.ts deleted file mode 100644 index 8b9c0e0308a..00000000000 --- a/projects/core/src/asm/store/selectors/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import * as AsmSelectors from './asm-group.selectors'; -export { AsmSelectors }; diff --git a/projects/core/src/auth/user-auth/events/user-auth-event.builder.spec.ts b/projects/core/src/auth/user-auth/events/user-auth-event.builder.spec.ts index 2ddb0ff8b90..0e6142ce3c8 100644 --- a/projects/core/src/auth/user-auth/events/user-auth-event.builder.spec.ts +++ b/projects/core/src/auth/user-auth/events/user-auth-event.builder.spec.ts @@ -4,16 +4,8 @@ import { TokenResponse } from 'angular-oauth2-oidc'; import { UserService } from 'projects/core/src/user/facade/user.service'; import { of, Subject } from 'rxjs'; import { map, take } from 'rxjs/operators'; -import { CsAgentAuthService } from '../../../asm/facade/csagent-auth.service'; -import { - AsmAuthStorageService, - TokenTarget, -} from '../../../asm/services/asm-auth-storage.service'; -import { ASM_FEATURE } from '../../../asm/store/asm-state'; -import * as fromReducers from '../../../asm/store/reducers/index'; import { EventService } from '../../../event/event.service'; import { User } from '../../../model/misc.model'; -import { UserIdService } from '../facade'; import { AuthService } from '../facade/auth.service'; import { AuthToken } from '../models/auth-token.model'; import { OAuthLibWrapperService } from '../services/oauth-lib-wrapper.service'; @@ -26,10 +18,6 @@ const authenticatedUser: AuthToken = { access_token: '123', access_token_stored_at: 'now', }; -const asmUser: AuthToken = { - access_token: '456', - access_token_stored_at: 'now', -}; const token$ = new Subject(); class MockAuthService implements Partial { @@ -37,27 +25,6 @@ class MockAuthService implements Partial { token$.asObservable().pipe(map((token) => !!token.access_token)); logout = () => token$.next(anonymousUser); } - -class MockAsmAuthStorageService implements Partial { - setEmulatedUserToken() {} - getEmulatedUserToken() { - return authenticatedUser; - } - setTokenTarget() {} - getTokenTarget() { - return of(TokenTarget.CSAgent); - } - getToken() { - return token$.asObservable(); - } - setToken(token: AuthToken) { - return token$.next(token); - } - switchTokenTargetToCSAgent() {} - switchTokenTargetToUser() {} - clearEmulatedUserToken() {} -} - class MockUserService implements Partial { get = () => of({} as User); } @@ -71,44 +38,27 @@ class MockOAuthLibWrapperService implements Partial { } } -class MockUserIdService implements Partial { - setUserId() {} - isEmulated() { - return of(false); - } -} - describe('UserAuthEventBuilder', () => { let actions$: Subject; let eventService: EventService; - let csAgentAuthService: CsAgentAuthService; - let userIdService: UserIdService; beforeEach(() => { actions$ = new Subject(); TestBed.configureTestingModule({ - imports: [ - StoreModule.forRoot({}), - StoreModule.forFeature(ASM_FEATURE, fromReducers.getReducers()), - ], + imports: [StoreModule.forRoot({})], providers: [ - { provide: UserIdService, useClass: MockUserIdService }, { provide: ActionsSubject, useValue: actions$ }, { provide: AuthService, useClass: MockAuthService }, - { provide: AsmAuthStorageService, useClass: MockAsmAuthStorageService }, { provide: UserService, useClass: MockUserService }, { provide: OAuthLibWrapperService, useClass: MockOAuthLibWrapperService, }, - CsAgentAuthService, ], }); TestBed.inject(UserAuthEventBuilder); // register events eventService = TestBed.inject(EventService); - csAgentAuthService = TestBed.inject(CsAgentAuthService); - userIdService = TestBed.inject(UserIdService); }); describe('LogoutEvent', () => { @@ -167,54 +117,6 @@ describe('UserAuthEventBuilder', () => { expect(result).toEqual(new LogoutEvent()); }); - - describe('ASM', () => { - it('should NOT fire when an ASM agent logs IN if a user was NOT authenticated', () => { - let result: LogoutEvent; - eventService - .get(LogoutEvent) - .pipe(take(1)) - .subscribe((value) => (result = value)); - - token$.next(anonymousUser); - - csAgentAuthService.authorizeCustomerSupportAgent('test', 'test'); - - expect(result).toBeUndefined(); - }); - - it('should NOT fire when an ASM agent logs OUT if an emulation session was in progress', async () => { - spyOn(userIdService, 'isEmulated').and.returnValue(of(true)); - - let result: LogoutEvent; - eventService - .get(LogoutEvent) - .pipe(take(1)) - .subscribe((value) => (result = value)); - - token$.next(asmUser); - - await csAgentAuthService.logoutCustomerSupportAgent(); - - expect(result).toBeUndefined(); - }); - - it('should NOT fire when an ASM agent logs OUT if an emulation session was NOT in progress', async () => { - spyOn(userIdService, 'isEmulated').and.returnValue(of(false)); - - let result: LogoutEvent; - eventService - .get(LogoutEvent) - .pipe(take(1)) - .subscribe((value) => (result = value)); - - token$.next(anonymousUser); - - await csAgentAuthService.logoutCustomerSupportAgent(); - - expect(result).toBeUndefined(); - }); - }); }); describe('LoginEvent', () => { @@ -245,19 +147,5 @@ describe('UserAuthEventBuilder', () => { actions$.next({ type: AuthActions.LOGIN }); expect(result).toEqual(new LoginEvent()); }); - - describe('ASM', () => { - it('should fire when starting customer emulation', () => { - let result: LoginEvent; - eventService - .get(LoginEvent) - .pipe(take(1)) - .subscribe((value) => (result = value)); - - csAgentAuthService.startCustomerEmulationSession('test id'); - - expect(result).toEqual(new LoginEvent()); - }); - }); }); }); diff --git a/projects/core/src/occ/adapters/asm/asm-occ.module.ts b/projects/core/src/occ/adapters/asm/asm-occ.module.ts deleted file mode 100644 index 096213882c4..00000000000 --- a/projects/core/src/occ/adapters/asm/asm-occ.module.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { AsmAdapter } from '../../../asm/connectors/asm.adapter'; -import { provideDefaultConfig } from '../../../config/config-providers'; -import { defaultOccAsmConfig } from './default-occ-asm-config'; -import { OccAsmAdapter } from './occ-asm.adapter'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -@NgModule({ - imports: [CommonModule], - providers: [ - provideDefaultConfig(defaultOccAsmConfig), - { - provide: AsmAdapter, - useClass: OccAsmAdapter, - }, - ], -}) -export class AsmOccModule {} diff --git a/projects/core/src/occ/adapters/asm/default-occ-asm-config.ts b/projects/core/src/occ/adapters/asm/default-occ-asm-config.ts deleted file mode 100644 index 76b01670f8d..00000000000 --- a/projects/core/src/occ/adapters/asm/default-occ-asm-config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { OccConfig } from '../../config/occ-config'; - -export const defaultOccAsmConfig: OccConfig = { - backend: { - occ: { - endpoints: { - asmCustomerSearch: '/assistedservicewebservices/customers/search', - }, - }, - }, -}; diff --git a/projects/core/src/occ/adapters/asm/index.ts b/projects/core/src/occ/adapters/asm/index.ts deleted file mode 100644 index fa659bc2d43..00000000000 --- a/projects/core/src/occ/adapters/asm/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './asm-occ.module'; -export * from './occ-asm.adapter'; diff --git a/projects/core/src/occ/adapters/asm/occ-asm.adapter.spec.ts b/projects/core/src/occ/adapters/asm/occ-asm.adapter.spec.ts deleted file mode 100644 index ab090cd12c2..00000000000 --- a/projects/core/src/occ/adapters/asm/occ-asm.adapter.spec.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { - HttpClientTestingModule, - HttpTestingController, - TestRequest, -} from '@angular/common/http/testing'; -import { TestBed } from '@angular/core/testing'; -import { Observable, of } from 'rxjs'; -import { AsmConfig } from '../../../asm/config/asm-config'; -import { CUSTOMER_SEARCH_PAGE_NORMALIZER } from '../../../asm/connectors/converters'; -import { - CustomerSearchOptions, - CustomerSearchPage, -} from '../../../asm/models/asm.models'; -import { User } from '../../../model/misc.model'; -import { BaseSiteService } from '../../../site-context/facade/base-site.service'; -import { ConverterService } from '../../../util/converter.service'; -import { - BaseOccUrlProperties, - DynamicAttributes, - OccEndpointsService, -} from '../../services'; -import { OccAsmAdapter } from './occ-asm.adapter'; - -const MockAsmConfig: AsmConfig = { - backend: { - occ: { - baseUrl: '', - }, - }, -}; - -const mockUser: User = { - displayUid: 'Display Uid', - firstName: 'First', - lastName: 'Last', - name: 'First Last', - uid: 'user@test.com', - customerId: '123456', -}; - -const mockCustomerSearchPage: CustomerSearchPage = { - entries: [mockUser], -} as CustomerSearchPage; - -const baseSite = 'test-site'; -const defaultSort = 'byNameAsc'; -class MockBaseSiteService { - getActive(): Observable { - return of(baseSite); - } -} - -class MockOccEndpointsService implements Partial { - buildUrl( - endpoint: string, - _attributes?: DynamicAttributes, - _propertiesToOmit?: BaseOccUrlProperties - ) { - return endpoint; - } -} - -describe('OccAsmAdapter', () => { - let occAsmAdapter: OccAsmAdapter; - let converterService: ConverterService; - let httpMock: HttpTestingController; - let occEnpointsService: OccEndpointsService; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - OccAsmAdapter, - { provide: BaseSiteService, useClass: MockBaseSiteService }, - { provide: AsmConfig, useValue: MockAsmConfig }, - { provide: OccEndpointsService, useClass: MockOccEndpointsService }, - ], - }); - - occAsmAdapter = TestBed.inject(OccAsmAdapter); - httpMock = TestBed.inject(HttpTestingController); - converterService = TestBed.inject(ConverterService); - occEnpointsService = TestBed.inject(OccEndpointsService); - spyOn(converterService, 'pipeable').and.callThrough(); - spyOn(occEnpointsService, 'buildUrl').and.callThrough(); - }); - - it('should be created', () => { - expect(occAsmAdapter).toBeTruthy(); - }); - - it('should perform a customer search with all params', () => { - let result: CustomerSearchPage; - const searchQuery = 'user@test.com'; - const pageSize = 10; - const searchOptions: CustomerSearchOptions = { - query: searchQuery, - pageSize, - }; - occAsmAdapter.customerSearch(searchOptions).subscribe((data) => { - result = data; - }); - const mockReq: TestRequest = httpMock.expectOne((req) => { - return req.method === 'GET'; - }); - - expect(mockReq.request.params.get('baseSite')).toBe(baseSite); - expect(mockReq.request.params.get('sort')).toBe(defaultSort); - expect(mockReq.request.params.get('query')).toBe(searchQuery); - expect(mockReq.request.params.get('pageSize')).toBe(pageSize + ''); - - expect(mockReq.cancelled).toBeFalsy(); - expect(mockReq.request.responseType).toEqual('json'); - mockReq.flush(mockCustomerSearchPage); - expect(result).toEqual(mockCustomerSearchPage); - expect(converterService.pipeable).toHaveBeenCalledWith( - CUSTOMER_SEARCH_PAGE_NORMALIZER - ); - expect(occEnpointsService.buildUrl).toHaveBeenCalledWith( - 'asmCustomerSearch', - {}, - { prefix: false, baseSite: false } - ); - }); - - it('should not include optional params if they are not in the options', () => { - let result: CustomerSearchPage; - const searchOptions: CustomerSearchOptions = {}; - occAsmAdapter.customerSearch(searchOptions).subscribe((data) => { - result = data; - }); - const mockReq: TestRequest = httpMock.expectOne((req) => { - return req.method === 'GET'; - }); - - expect(mockReq.request.params.get('baseSite')).toBe(baseSite); - expect(mockReq.request.params.get('sort')).toBe(defaultSort); - expect(mockReq.request.params.get('query')).toBeNull(); - expect(mockReq.request.params.get('pageSize')).toBeNull(); - - expect(mockReq.cancelled).toBeFalsy(); - expect(mockReq.request.responseType).toEqual('json'); - mockReq.flush(mockCustomerSearchPage); - expect(result).toEqual(mockCustomerSearchPage); - expect(converterService.pipeable).toHaveBeenCalledWith( - CUSTOMER_SEARCH_PAGE_NORMALIZER - ); - expect(occEnpointsService.buildUrl).toHaveBeenCalledWith( - 'asmCustomerSearch', - {}, - { prefix: false, baseSite: false } - ); - }); - - it('should perform a customer search with pageSize 0', () => { - let result: CustomerSearchPage; - const searchQuery = 'user@test.com'; - const pageSize = 0; - const searchOptions: CustomerSearchOptions = { - query: searchQuery, - pageSize, - }; - occAsmAdapter.customerSearch(searchOptions).subscribe((data) => { - result = data; - }); - const mockReq: TestRequest = httpMock.expectOne((req) => { - return req.method === 'GET'; - }); - - expect(mockReq.request.params.get('baseSite')).toBe(baseSite); - expect(mockReq.request.params.get('sort')).toBe(defaultSort); - expect(mockReq.request.params.get('query')).toBe(searchQuery); - expect(mockReq.request.params.get('pageSize')).toBe(pageSize + ''); - - expect(mockReq.cancelled).toBeFalsy(); - expect(mockReq.request.responseType).toEqual('json'); - mockReq.flush(mockCustomerSearchPage); - expect(result).toEqual(mockCustomerSearchPage); - expect(converterService.pipeable).toHaveBeenCalledWith( - CUSTOMER_SEARCH_PAGE_NORMALIZER - ); - expect(occEnpointsService.buildUrl).toHaveBeenCalledWith( - 'asmCustomerSearch', - {}, - { prefix: false, baseSite: false } - ); - }); -}); diff --git a/projects/core/src/occ/adapters/asm/occ-asm.adapter.ts b/projects/core/src/occ/adapters/asm/occ-asm.adapter.ts deleted file mode 100644 index 2a1d5446e8c..00000000000 --- a/projects/core/src/occ/adapters/asm/occ-asm.adapter.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; -import { AsmConfig } from '../../../asm/config/asm-config'; -import { AsmAdapter } from '../../../asm/connectors/asm.adapter'; -import { CUSTOMER_SEARCH_PAGE_NORMALIZER } from '../../../asm/connectors/converters'; -import { - CustomerSearchOptions, - CustomerSearchPage, -} from '../../../asm/models/asm.models'; -import { BaseSiteService } from '../../../site-context/facade/base-site.service'; -import { ConverterService } from '../../../util/converter.service'; -import { OccEndpointsService } from '../../services/occ-endpoints.service'; -import { - InterceptorUtil, - USE_CUSTOMER_SUPPORT_AGENT_TOKEN, -} from '../../utils/interceptor-util'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -@Injectable() -export class OccAsmAdapter implements AsmAdapter { - private activeBaseSite: string; - - constructor( - protected http: HttpClient, - protected occEndpointsService: OccEndpointsService, - protected converterService: ConverterService, - protected config: AsmConfig, - protected baseSiteService: BaseSiteService - ) { - this.baseSiteService - .getActive() - .subscribe((value) => (this.activeBaseSite = value)); - } - - customerSearch( - options: CustomerSearchOptions - ): Observable { - const headers = InterceptorUtil.createHeader( - USE_CUSTOMER_SUPPORT_AGENT_TOKEN, - true, - new HttpHeaders() - ); - let params: HttpParams = new HttpParams() - .set('baseSite', this.activeBaseSite) - .set('sort', 'byNameAsc'); - - if (typeof options['query'] !== 'undefined') { - params = params.set('query', '' + options.query); - } - - if (typeof options['pageSize'] !== 'undefined') { - params = params.set('pageSize', '' + options.pageSize); - } - - const url = this.occEndpointsService.buildUrl( - 'asmCustomerSearch', - {}, - { prefix: false, baseSite: false } - ); - - return this.http - .get(url, { headers, params }) - .pipe(this.converterService.pipeable(CUSTOMER_SEARCH_PAGE_NORMALIZER)); - } -} diff --git a/projects/core/src/occ/adapters/index.ts b/projects/core/src/occ/adapters/index.ts index d6a192572e4..9886f26bf30 100644 --- a/projects/core/src/occ/adapters/index.ts +++ b/projects/core/src/occ/adapters/index.ts @@ -1,4 +1,3 @@ -export * from './asm/index'; export * from './cart/index'; export * from './checkout/index'; export * from './cms/index'; diff --git a/projects/core/src/occ/occ-models/occ-endpoints.model.ts b/projects/core/src/occ/occ-models/occ-endpoints.model.ts index 86d70b17b23..3844f08a5ee 100644 --- a/projects/core/src/occ/occ-models/occ-endpoints.model.ts +++ b/projects/core/src/occ/occ-models/occ-endpoints.model.ts @@ -338,12 +338,6 @@ export interface OccEndpoints { * @member {string} */ consignmentTracking?: string | OccEndpoint; - /** - * Endpoint for asm customer search - * - * @member {string} - */ - asmCustomerSearch?: string | OccEndpoint; /** * Endpoint for cart voucher * diff --git a/projects/core/src/occ/occ.module.ts b/projects/core/src/occ/occ.module.ts index 7bc38265a57..c580eb4f882 100644 --- a/projects/core/src/occ/occ.module.ts +++ b/projects/core/src/occ/occ.module.ts @@ -2,7 +2,6 @@ import { HTTP_INTERCEPTORS } from '@angular/common/http'; import { ModuleWithProviders, NgModule } from '@angular/core'; import { provideDefaultConfig } from '../config/config-providers'; import { provideConfigValidator } from '../config/config-validator/config-validator'; -import { AsmOccModule } from './adapters/asm/asm-occ.module'; import { CartOccModule } from './adapters/cart/cart-occ.module'; import { CheckoutOccModule } from './adapters/checkout/checkout-occ.module'; import { CmsOccModule } from './adapters/cms/cms-occ.module'; @@ -20,7 +19,6 @@ import { WithCredentialsInterceptor } from './interceptors/with-credentials.inte */ @NgModule({ imports: [ - AsmOccModule, CmsOccModule, CartOccModule, CheckoutOccModule, diff --git a/projects/core/src/occ/services/occ-endpoints.service.spec.ts b/projects/core/src/occ/services/occ-endpoints.service.spec.ts index 82b3b85ea89..7b2532a1138 100644 --- a/projects/core/src/occ/services/occ-endpoints.service.spec.ts +++ b/projects/core/src/occ/services/occ-endpoints.service.spec.ts @@ -15,7 +15,8 @@ describe('OccEndpointsService', () => { baseUrl: 'test-baseUrl', prefix: '/test-occPrefix', endpoints: { - asmCustomerSearch: '/assistedservicewebservices/customers/search', + regions: + '/countries/${isoCode}/regions?fields=regions(name,isocode,isocodeShort)', product: { default: 'configured-endpoint1/${test}?fields=abc', test: 'configured-endpoint1/${test}?fields=test', @@ -50,22 +51,22 @@ describe('OccEndpointsService', () => { it('should return raw endpoint', () => { const occ = mockOccConfig.backend.occ; - expect(service.getRawEndpoint('asmCustomerSearch')).toEqual( - occ.baseUrl + occ.endpoints['asmCustomerSearch'] + expect(service.getRawEndpoint('regions')).toEqual( + occ.baseUrl + occ.endpoints['regions'] ); }); it('should return raw endpoint value', () => { const occ = mockOccConfig.backend.occ; - expect(service.getRawEndpointValue('asmCustomerSearch')).toEqual( - occ.endpoints['asmCustomerSearch'].toString() + expect(service.getRawEndpointValue('regions')).toEqual( + occ.endpoints['regions'].toString() ); }); it('should return occ endpoint', () => { const occ = mockOccConfig.backend.occ; - expect(service.getOccEndpoint('asmCustomerSearch')).toEqual( - occ.baseUrl + occ.prefix + occ.endpoints['asmCustomerSearch'] + expect(service.getOccEndpoint('regions')).toEqual( + occ.baseUrl + occ.prefix + occ.endpoints['regions'] ); }); @@ -81,7 +82,7 @@ describe('OccEndpointsService', () => { describe('isConfigured', () => { it('should return true when the endpoint is configured', () => { - expect(service.isConfigured('asmCustomerSearch')).toBe(true); + expect(service.isConfigured('regions')).toBe(true); }); it('should return false when endpoint is not configured', () => { diff --git a/projects/core/src/personalization/config/default-personalization-config.ts b/projects/core/src/personalization/config/default-personalization-config.ts deleted file mode 100644 index 3aa4fa9fb0a..00000000000 --- a/projects/core/src/personalization/config/default-personalization-config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { PersonalizationConfig } from './personalization-config'; - -/** - * @deprecated since 3.2, use @spartacus/tracking/personalization instead - */ -export const defaultPersonalizationConfig: PersonalizationConfig = { - personalization: { - enabled: false, - httpHeaderName: { - id: 'Occ-Personalization-Id', - timestamp: 'Occ-Personalization-Time', - }, - context: { - slotPosition: 'PlaceholderContentSlot', - componentId: 'PersonalizationScriptComponent', - }, - }, -}; diff --git a/projects/core/src/personalization/config/personalization-config.ts b/projects/core/src/personalization/config/personalization-config.ts deleted file mode 100644 index a71056c0cfc..00000000000 --- a/projects/core/src/personalization/config/personalization-config.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Config } from '../../config/config-tokens'; - -/** - * @deprecated since 3.2, use @spartacus/tracking/personalization instead - */ -@Injectable({ - providedIn: 'root', - useExisting: Config, -}) -export abstract class PersonalizationConfig { - personalization: { - enabled?: boolean; - httpHeaderName?: { - id: string; - timestamp: string; - }; - context?: { - slotPosition?: string; - componentId?: string; - }; - }; -} diff --git a/projects/core/src/personalization/http-interceptors/index.ts b/projects/core/src/personalization/http-interceptors/index.ts deleted file mode 100644 index 8d6f885e686..00000000000 --- a/projects/core/src/personalization/http-interceptors/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Provider } from '@angular/core'; -import { HTTP_INTERCEPTORS } from '@angular/common/http'; - -import { OccPersonalizationIdInterceptor } from './occ-personalization-id.interceptor'; -import { OccPersonalizationTimeInterceptor } from './occ-personalization-time.interceptor'; - -export const interceptors: Provider[] = [ - { - provide: HTTP_INTERCEPTORS, - useExisting: OccPersonalizationIdInterceptor, - multi: true, - }, - { - provide: HTTP_INTERCEPTORS, - useExisting: OccPersonalizationTimeInterceptor, - multi: true, - }, -]; diff --git a/projects/core/src/personalization/http-interceptors/occ-personalization-id.interceptor.spec.ts b/projects/core/src/personalization/http-interceptors/occ-personalization-id.interceptor.spec.ts deleted file mode 100644 index dc960eb5769..00000000000 --- a/projects/core/src/personalization/http-interceptors/occ-personalization-id.interceptor.spec.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http'; -import { - HttpClientTestingModule, - HttpTestingController, -} from '@angular/common/http/testing'; -import { inject, TestBed } from '@angular/core/testing'; -import { OccEndpointsService } from '../../occ/services/occ-endpoints.service'; -import { WindowRef } from '../../window/window-ref'; -import { PersonalizationConfig } from '../config/personalization-config'; -import { OccPersonalizationIdInterceptor } from './occ-personalization-id.interceptor'; - -const mockPersonalizationConfig: PersonalizationConfig = { - personalization: { - enabled: true, - httpHeaderName: { - id: 'test-personalization-id', - timestamp: 'test-personalization-time', - }, - }, -}; - -const store = {}; -const MockWindowRef = { - localStorage: { - getItem: (key: string): string => { - return key in store ? store[key] : null; - }, - setItem: (key: string, value: string) => { - store[key] = `${value}`; - }, - removeItem: (key: string): void => { - if (key in store) { - store[key] = undefined; - } - }, - }, -}; -const endpoint = '/test'; -class OccEndpointsServiceMock { - getBaseEndpoint(): string { - return endpoint; - } -} -describe('OccPersonalizationIdInterceptor with personalization enabled', () => { - let httpMock: HttpTestingController; - let winRef: WindowRef; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { provide: PersonalizationConfig, useValue: mockPersonalizationConfig }, - { provide: WindowRef, useValue: MockWindowRef }, - { provide: OccEndpointsService, useClass: OccEndpointsServiceMock }, - { - provide: HTTP_INTERCEPTORS, - useClass: OccPersonalizationIdInterceptor, - multi: true, - }, - ], - }); - - httpMock = TestBed.inject(HttpTestingController); - winRef = TestBed.inject(WindowRef); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should add request header if the personalization-id exists', inject( - [HttpClient], - (http: HttpClient) => { - winRef.localStorage.setItem('personalization-id', 'test id'); - - http.get('https://localhost:9002/test').subscribe((result) => { - expect(result).toBeTruthy(); - }); - - const mockReq = httpMock.expectOne((req) => { - return req.method === 'GET'; - }); - - const perHeader: string = mockReq.request.headers.get( - 'test-personalization-id' - ); - expect(perHeader).toBeTruthy(); - expect(perHeader).toEqual('test id'); - - mockReq.flush('someData'); - } - )); - - it('should keep the new personalization-id, if it is different from the existing id ', inject( - [HttpClient], - (http: HttpClient) => { - winRef.localStorage.setItem('personalization-id', 'old id'); - - http.get('https://localhost:9002/test').subscribe((response) => { - expect(response).toEqual(''); - }); - - const mockReq = httpMock.expectOne((req) => { - return req.method === 'GET'; - }); - mockReq.flush('', { headers: { ['test-personalization-id']: 'new id' } }); - expect(winRef.localStorage.getItem('personalization-id')).toEqual( - 'new id' - ); - } - )); -}); - -describe('OccPersonalizationIdInterceptor with personalization disabled', () => { - let httpMock: HttpTestingController; - let winRef: WindowRef; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { - provide: PersonalizationConfig, - useValue: { - personalization: { - enabled: false, - }, - }, - }, - { provide: WindowRef, useValue: MockWindowRef }, - { provide: OccEndpointsService, useClass: OccEndpointsServiceMock }, - { - provide: HTTP_INTERCEPTORS, - useClass: OccPersonalizationIdInterceptor, - multi: true, - }, - ], - }); - - httpMock = TestBed.inject(HttpTestingController); - winRef = TestBed.inject(WindowRef); - - winRef.localStorage.setItem('personalization-id', 'test id'); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should clear client-side personalization-id, and not send it in request header', inject( - [HttpClient], - (http: HttpClient) => { - http.get('https://localhost:9002/test').subscribe((result) => { - expect(result).toBeTruthy(); - }); - const mockReq = httpMock.expectOne((req) => { - return req.method === 'GET'; - }); - const perHeader: string = mockReq.request.headers.get( - 'test-personalization-id' - ); - expect(perHeader).toBeNull(); - mockReq.flush('someData'); - - expect(winRef.localStorage.getItem('personalization-id')).toBeUndefined(); - } - )); -}); diff --git a/projects/core/src/personalization/http-interceptors/occ-personalization-id.interceptor.ts b/projects/core/src/personalization/http-interceptors/occ-personalization-id.interceptor.ts deleted file mode 100644 index 4d25e54efd8..00000000000 --- a/projects/core/src/personalization/http-interceptors/occ-personalization-id.interceptor.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; -import { - HttpEvent, - HttpHandler, - HttpInterceptor, - HttpRequest, - HttpResponse, -} from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; - -import { OccEndpointsService } from '../../occ/services/occ-endpoints.service'; -import { PersonalizationConfig } from '../config/personalization-config'; -import { WindowRef } from '../../window/window-ref'; -import { isPlatformBrowser } from '@angular/common'; - -const PERSONALIZATION_ID_KEY = 'personalization-id'; - -@Injectable({ providedIn: 'root' }) -export class OccPersonalizationIdInterceptor implements HttpInterceptor { - private personalizationId: string; - private requestHeader: string; - private enabled = false; - - constructor( - private config: PersonalizationConfig, - private occEndpoints: OccEndpointsService, - private winRef: WindowRef, - @Inject(PLATFORM_ID) private platform: any - ) { - if (isPlatformBrowser(this.platform)) { - this.enabled = - (this.winRef.localStorage && this.config.personalization.enabled) || - false; - - if (this.enabled) { - this.requestHeader = this.config.personalization.httpHeaderName.id.toLowerCase(); - this.personalizationId = this.winRef.localStorage.getItem( - PERSONALIZATION_ID_KEY - ); - } else if (this.winRef.localStorage.getItem(PERSONALIZATION_ID_KEY)) { - this.winRef.localStorage.removeItem(PERSONALIZATION_ID_KEY); - } - } - } - - intercept( - request: HttpRequest, - next: HttpHandler - ): Observable> { - if (!this.enabled) { - return next.handle(request); - } - - if ( - this.personalizationId && - request.url.includes(this.occEndpoints.getBaseEndpoint()) - ) { - request = request.clone({ - setHeaders: { - [this.requestHeader]: this.personalizationId, - }, - }); - } - - return next.handle(request).pipe( - tap((event) => { - if (event instanceof HttpResponse) { - if (event.headers.keys().includes(this.requestHeader)) { - const receivedId = event.headers.get(this.requestHeader); - if (this.personalizationId !== receivedId) { - this.personalizationId = receivedId; - this.winRef.localStorage.setItem( - PERSONALIZATION_ID_KEY, - this.personalizationId - ); - } - } - } - }) - ); - } -} diff --git a/projects/core/src/personalization/http-interceptors/occ-personalization-time.interceptor.spec.ts b/projects/core/src/personalization/http-interceptors/occ-personalization-time.interceptor.spec.ts deleted file mode 100644 index 8673059fd05..00000000000 --- a/projects/core/src/personalization/http-interceptors/occ-personalization-time.interceptor.spec.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { HTTP_INTERCEPTORS, HttpClient } from '@angular/common/http'; -import { - HttpClientTestingModule, - HttpTestingController, -} from '@angular/common/http/testing'; -import { inject, TestBed } from '@angular/core/testing'; -import { OccEndpointsService } from '../../occ/services/occ-endpoints.service'; -import { WindowRef } from '../../window/window-ref'; -import { PersonalizationConfig } from '../config/personalization-config'; -import { OccPersonalizationTimeInterceptor } from './occ-personalization-time.interceptor'; - -const mockPersonalizationConfig: PersonalizationConfig = { - personalization: { - enabled: true, - httpHeaderName: { - id: 'test-personalization-id', - timestamp: 'test-personalization-time', - }, - }, -}; -const store = {}; -const MockWindowRef = { - localStorage: { - getItem: (key: string): string => { - return key in store ? store[key] : null; - }, - setItem: (key: string, value: string) => { - store[key] = `${value}`; - }, - removeItem: (key: string): void => { - if (key in store) { - store[key] = undefined; - } - }, - }, -}; -const endpoint = '/test'; -class OccEndpointsServiceMock { - getBaseEndpoint(): string { - return endpoint; - } -} -describe('OccPersonalizationTimeInterceptor with personalization enabled', () => { - let httpMock: HttpTestingController; - let winRef: WindowRef; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { provide: PersonalizationConfig, useValue: mockPersonalizationConfig }, - { provide: WindowRef, useValue: MockWindowRef }, - { provide: OccEndpointsService, useClass: OccEndpointsServiceMock }, - { - provide: HTTP_INTERCEPTORS, - useClass: OccPersonalizationTimeInterceptor, - multi: true, - }, - ], - }); - - httpMock = TestBed.inject(HttpTestingController); - winRef = TestBed.inject(WindowRef); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should add request header if the personalization-time exists', inject( - [HttpClient], - (http: HttpClient) => { - winRef.localStorage.setItem('personalization-time', 'test timestamp'); - - http.get('https://localhost:9002/test').subscribe((result) => { - expect(result).toBeTruthy(); - }); - - const mockReq = httpMock.expectOne((req) => { - return req.method === 'GET'; - }); - - const perHeader: string = mockReq.request.headers.get( - 'test-personalization-time' - ); - expect(perHeader).toBeTruthy(); - expect(perHeader).toEqual('test timestamp'); - - mockReq.flush('someData'); - } - )); - - it('should keep the new personalization-time, if it is different from the existing time', inject( - [HttpClient], - (http: HttpClient) => { - winRef.localStorage.setItem('personalization-time', 'old timestamp'); - - http.get('https://localhost:9002/test').subscribe((response) => { - expect(response).toEqual(''); - }); - - const mockReq = httpMock.expectOne((req) => { - return req.method === 'GET'; - }); - mockReq.flush('', { - headers: { ['test-personalization-time']: 'new timestamp' }, - }); - expect(winRef.localStorage.getItem('personalization-time')).toEqual( - 'new timestamp' - ); - } - )); -}); - -describe('OccPersonalizationIdInterceptor with personalization disabled', () => { - let httpMock: HttpTestingController; - let winRef: WindowRef; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - { - provide: PersonalizationConfig, - useValue: { - personalization: { - enabled: false, - }, - }, - }, - { provide: WindowRef, useValue: MockWindowRef }, - { provide: OccEndpointsService, useClass: OccEndpointsServiceMock }, - { - provide: HTTP_INTERCEPTORS, - useClass: OccPersonalizationTimeInterceptor, - multi: true, - }, - ], - }); - - httpMock = TestBed.inject(HttpTestingController); - winRef = TestBed.inject(WindowRef); - - winRef.localStorage.setItem('personalization-id', 'test id'); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should clear client-side personalization-id, and not send it in request header', inject( - [HttpClient], - (http: HttpClient) => { - http.get('https://localhost:9002/test').subscribe((result) => { - expect(result).toBeTruthy(); - }); - const mockReq = httpMock.expectOne((req) => { - return req.method === 'GET'; - }); - const perHeader: string = mockReq.request.headers.get( - 'test-personalization-time' - ); - expect(perHeader).toBeNull(); - mockReq.flush('someData'); - - expect( - winRef.localStorage.getItem('personalization-time') - ).toBeUndefined(); - } - )); -}); diff --git a/projects/core/src/personalization/http-interceptors/occ-personalization-time.interceptor.ts b/projects/core/src/personalization/http-interceptors/occ-personalization-time.interceptor.ts deleted file mode 100644 index bad3a0118f0..00000000000 --- a/projects/core/src/personalization/http-interceptors/occ-personalization-time.interceptor.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Inject, Injectable, PLATFORM_ID } from '@angular/core'; -import { - HttpEvent, - HttpHandler, - HttpInterceptor, - HttpRequest, - HttpResponse, -} from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; - -import { OccEndpointsService } from '../../occ/services/occ-endpoints.service'; -import { PersonalizationConfig } from '../config/personalization-config'; -import { WindowRef } from '../../window/window-ref'; -import { isPlatformBrowser } from '@angular/common'; - -const PERSONALIZATION_TIME_KEY = 'personalization-time'; - -@Injectable({ providedIn: 'root' }) -export class OccPersonalizationTimeInterceptor implements HttpInterceptor { - private timestamp: string; - private requestHeader: string; - private enabled = false; - - constructor( - private config: PersonalizationConfig, - private occEndpoints: OccEndpointsService, - private winRef: WindowRef, - @Inject(PLATFORM_ID) private platform: any - ) { - if (isPlatformBrowser(this.platform)) { - this.enabled = - (this.winRef.localStorage && this.config.personalization.enabled) || - false; - - if (this.enabled) { - this.requestHeader = this.config.personalization.httpHeaderName.timestamp.toLowerCase(); - this.timestamp = this.winRef.localStorage.getItem( - PERSONALIZATION_TIME_KEY - ); - } else if (this.winRef.localStorage.getItem(PERSONALIZATION_TIME_KEY)) { - this.winRef.localStorage.removeItem(PERSONALIZATION_TIME_KEY); - } - } - } - - intercept( - request: HttpRequest, - next: HttpHandler - ): Observable> { - if (!this.enabled) { - return next.handle(request); - } - - if ( - this.timestamp && - request.url.includes(this.occEndpoints.getBaseEndpoint()) - ) { - request = request.clone({ - setHeaders: { - [this.requestHeader]: this.timestamp, - }, - }); - } - - return next.handle(request).pipe( - tap((event) => { - if (event instanceof HttpResponse) { - if (event.headers.keys().includes(this.requestHeader)) { - const receivedTimestamp = event.headers.get(this.requestHeader); - if (this.timestamp !== receivedTimestamp) { - this.timestamp = receivedTimestamp; - this.winRef.localStorage.setItem( - PERSONALIZATION_TIME_KEY, - this.timestamp - ); - } - } - } - }) - ); - } -} diff --git a/projects/core/src/personalization/index.ts b/projects/core/src/personalization/index.ts deleted file mode 100644 index e5513d12d1d..00000000000 --- a/projects/core/src/personalization/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export * from './personalization.module'; -export * from './config/personalization-config'; -export * from './services/personalization-context.service'; -export * from './model/personalization-context.model'; diff --git a/projects/core/src/personalization/model/personalization-context.model.ts b/projects/core/src/personalization/model/personalization-context.model.ts deleted file mode 100644 index a88c24de4d2..00000000000 --- a/projects/core/src/personalization/model/personalization-context.model.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @deprecated since 3.2, use @spartacus/tracking/personalization instead - */ -export interface PersonalizationAction { - action_name: string; - action_type: string; - customization_name?: string; - customization_code?: string; - variation_name?: string; - variation_code?: string; -} - -/** - * @deprecated since 3.2, use @spartacus/tracking/personalization instead - */ -export interface PersonalizationContext { - actions: PersonalizationAction[]; - segments: string[]; -} diff --git a/projects/core/src/personalization/personalization.module.ts b/projects/core/src/personalization/personalization.module.ts deleted file mode 100644 index a6b2cd499f3..00000000000 --- a/projects/core/src/personalization/personalization.module.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ModuleWithProviders, NgModule } from '@angular/core'; -import { provideDefaultConfig } from '../config/config-providers'; -import { defaultPersonalizationConfig } from './config/default-personalization-config'; -import { interceptors } from './http-interceptors/index'; - -/** - * @deprecated since 3.2, use @spartacus/tracking/personalization instead - */ -@NgModule({}) -export class PersonalizationModule { - static forRoot(): ModuleWithProviders { - return { - ngModule: PersonalizationModule, - providers: [ - provideDefaultConfig(defaultPersonalizationConfig), - ...interceptors, - ], - }; - } -} diff --git a/projects/core/src/personalization/services/personalization-context.service.spec.ts b/projects/core/src/personalization/services/personalization-context.service.spec.ts deleted file mode 100644 index 64400707a32..00000000000 --- a/projects/core/src/personalization/services/personalization-context.service.spec.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { Observable, of } from 'rxjs'; -import { - CmsService, - Page, - PageType, - PersonalizationConfig, - PersonalizationContext, - PersonalizationContextService, -} from '@spartacus/core'; - -const mockPersonalizationConfig: PersonalizationConfig = { - personalization: { - enabled: true, - context: { - slotPosition: 'PlaceholderContentSlot', - componentId: 'PersonalizationScriptComponent', - }, - }, -}; - -const personalizationContext = { - actions: [ - { - customization_name: btoa('customization_name1'), - customization_code: btoa('customization_code1'), - variation_name: btoa('variation_name1'), - variation_code: btoa('variation_code1'), - action_name: btoa('action_name1'), - action_type: btoa('action_type1'), - }, - { - customization_name: btoa('customization_name2'), - customization_code: btoa('customization_code2'), - variation_name: btoa('variation_name2'), - variation_code: btoa('variation_code2'), - action_name: btoa('action_name2'), - action_type: btoa('action_type2'), - }, - ], - segments: [btoa('segment1'), btoa('segment2')], -}; - -const personalizationContextBase64 = btoa( - JSON.stringify(personalizationContext) -); - -const mockContentPage: Page = { - type: PageType.CONTENT_PAGE, - template: 'CartPageTemplate', - title: 'Shopping Cart', - slots: { - PlaceholderContentSlot: { - components: [ - { - uid: 'PersonalizationScriptComponent', - properties: { - script: { - data: personalizationContextBase64, - }, - }, - }, - ], - }, - }, -}; - -class MockCmsService { - getCurrentPage(): Observable { - return of(mockContentPage); - } -} - -describe('PersonalizationContextService', () => { - let service: PersonalizationContextService; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - PersonalizationContextService, - { provide: PersonalizationConfig, useValue: mockPersonalizationConfig }, - { provide: CmsService, useClass: MockCmsService }, - ], - }); - - service = TestBed.inject(PersonalizationContextService); - }); - - it('should return personalization context if PersonalizationScriptComponent exists', () => { - let result: PersonalizationContext; - service - .getPersonalizationContext() - .subscribe((value) => { - result = value; - }) - .unsubscribe(); - - expect(result.segments[0]).toEqual('segment1'); - expect(result.segments[1]).toEqual('segment2'); - expect(result.actions[0].customization_code).toEqual('customization_code1'); - expect(result.actions[1].customization_code).toEqual('customization_code2'); - expect(result.actions[0].variation_name).toEqual('variation_name1'); - expect(result.actions[0].variation_code).toEqual('variation_code1'); - expect(result.actions[0].action_name).toEqual('action_name1'); - expect(result.actions[0].action_type).toEqual('action_type1'); - }); -}); diff --git a/projects/core/src/personalization/services/personalization-context.service.ts b/projects/core/src/personalization/services/personalization-context.service.ts deleted file mode 100644 index f5fd454bf78..00000000000 --- a/projects/core/src/personalization/services/personalization-context.service.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { Injectable, isDevMode } from '@angular/core'; -import { EMPTY, Observable } from 'rxjs'; -import { filter, map } from 'rxjs/operators'; -import { CmsService } from '../../cms/facade/cms.service'; -import { ContentSlotComponentData } from '../../cms/model/content-slot-component-data.model'; -import { ContentSlotData } from '../../cms/model/content-slot-data.model'; -import { Page } from '../../cms/model/page.model'; -import { PersonalizationConfig } from '../config/personalization-config'; -import { PersonalizationContext } from '../model/personalization-context.model'; - -/** - * @deprecated since 3.2, use @spartacus/tracking/personalization instead - */ -@Injectable({ - providedIn: 'root', -}) -export class PersonalizationContextService { - constructor( - protected config: PersonalizationConfig, - protected cmsService: CmsService - ) {} - - getPersonalizationContext(): Observable { - if (!this.config.personalization?.context) { - if (isDevMode()) { - console.warn(`There is no context configured in Personalization`); - } - return EMPTY; - } - return this.cmsService.getCurrentPage().pipe( - filter(Boolean), - map( - (page: Page) => - page.slots[this.config.personalization.context.slotPosition] - ), - filter(Boolean), - map((slot: ContentSlotData) => - slot.components?.find( - (i) => i.uid === this.config.personalization.context.componentId - ) - ), - filter(Boolean), - map((component: ContentSlotComponentData) => - this.buildPersonalizationContext(component.properties.script.data) - ) - ); - } - - private buildPersonalizationContext(data: string): PersonalizationContext { - const context = JSON.parse(atob(data)); - context.actions.forEach((action) => { - Object.keys(action).forEach((key) => { - action[key] = atob(action[key]); - }); - }); - for (let i = 0; i < context.segments.length; i++) { - context.segments[i] = atob(context.segments[i]); - } - return context; - } -} diff --git a/projects/core/src/site-context/facade/base-site.service.spec.ts b/projects/core/src/site-context/facade/base-site.service.spec.ts index 06993545cb2..f4cd5ba963c 100644 --- a/projects/core/src/site-context/facade/base-site.service.spec.ts +++ b/projects/core/src/site-context/facade/base-site.service.spec.ts @@ -22,6 +22,12 @@ const mockBaseSitesSelect = createSpy('select').and.returnValue(() => of([{ uid: 'mock-active-base-site-uid' }, { uid: 'test-baseSite' }]) ); +const mockSiteContextConfig: SiteContextConfig = { + context: { + baseSite: ['electronics-spa'], + }, +}; + describe('BaseSiteService', () => { let service: BaseSiteService; let store: Store; @@ -39,7 +45,7 @@ describe('BaseSiteService', () => { provide: SiteAdapter, useValue: {}, }, - { provide: SiteContextConfig, useValue: {} }, + { provide: SiteContextConfig, useValue: mockSiteContextConfig }, ], }); store = TestBed.inject(Store); @@ -121,4 +127,20 @@ describe('BaseSiteService', () => { service.get('test-baseSite').subscribe((res) => (result = res)); expect(result).toEqual({ uid: 'test-baseSite' }); }); + + describe('isInitialized', () => { + it('should return TRUE if a base site is initialized', () => { + spyOnProperty(ngrxStore, 'select').and.returnValues(mockBaseSitesSelect); + expect(service.isInitialized()).toBeTruthy(); + }); + }); + + describe('isValid', () => { + it('should return TRUE if the base site is valid', () => { + expect(service['isValid']('electronics-spa')).toBeTruthy(); + }); + it('should return FALSE if the base site is not valid', () => { + expect(service['isValid']('something-else')).toBeFalsy(); + }); + }); }); diff --git a/projects/core/src/site-context/facade/base-site.service.ts b/projects/core/src/site-context/facade/base-site.service.ts index b34b0b8fe3f..41e887fe257 100644 --- a/projects/core/src/site-context/facade/base-site.service.ts +++ b/projects/core/src/site-context/facade/base-site.service.ts @@ -3,7 +3,7 @@ import { select, Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { filter, map, switchMap, take, tap } from 'rxjs/operators'; import { BaseSite } from '../../model/misc.model'; -import { getContextParameterDefault } from '../config/context-config-utils'; +import { getContextParameterValues } from '../config/context-config-utils'; import { SiteContextConfig } from '../config/site-context-config'; import { BASE_SITE_CONTEXT_ID } from '../providers/context-ids'; import { SiteContextActions } from '../store/actions/index'; @@ -75,20 +75,28 @@ export class BaseSiteService implements SiteContext { } /** - * Initializes the active baseSite. + * Tells whether the value of the base site has been already initialized */ - initialize(): void { - let value; + isInitialized(): boolean { + let valueInitialized = false; this.getActive() - .subscribe((val) => (value = val)) + .subscribe(() => (valueInitialized = true)) .unsubscribe(); - if (value) { - // don't initialize, if there is already a value (i.e. retrieved from route or transferred from SSR) - return; - } - this.setActive( - getContextParameterDefault(this.config, BASE_SITE_CONTEXT_ID) + return valueInitialized; + } + + /** + * Tells whether the given iso code is allowed. + * + * The list of allowed iso codes can be configured in the `context` config of Spartacus. + */ + protected isValid(value: string): boolean { + return ( + !!value && + getContextParameterValues(this.config, BASE_SITE_CONTEXT_ID).includes( + value + ) ); } } diff --git a/projects/core/src/site-context/facade/currency.service.spec.ts b/projects/core/src/site-context/facade/currency.service.spec.ts index 2b7d0b82665..508a6cc77f5 100644 --- a/projects/core/src/site-context/facade/currency.service.spec.ts +++ b/projects/core/src/site-context/facade/currency.service.spec.ts @@ -20,7 +20,7 @@ const mockActiveCurr = 'USD'; const mockSiteContextConfig: SiteContextConfig = { context: { - currency: ['USD'], + currency: ['USD', 'JPY'], }, }; @@ -102,9 +102,9 @@ describe('CurrencyService', () => { describe('setActive(isocode)', () => { it('should be able to set active currency', () => { spyOnProperty(ngrxStore, 'select').and.returnValues(mockSelect2); - service.setActive('EUR'); + service.setActive('JPY'); expect(store.dispatch).toHaveBeenCalledWith( - new SiteContextActions.SetActiveCurrency('EUR') + new SiteContextActions.SetActiveCurrency('JPY') ); }); @@ -116,4 +116,20 @@ describe('CurrencyService', () => { ); }); }); + + describe('isInitialized', () => { + it('should return TRUE if a currency is initialized', () => { + spyOnProperty(ngrxStore, 'select').and.returnValues(mockSelect1); + expect(service.isInitialized()).toBeTruthy(); + }); + }); + + describe('isValid', () => { + it('should return TRUE if the iso is valid', () => { + expect(service['isValid'](mockActiveCurr)).toBeTruthy(); + }); + it('should return FALSE if the iso is not valid', () => { + expect(service['isValid']('EUR')).toBeFalsy(); + }); + }); }); diff --git a/projects/core/src/site-context/facade/currency.service.ts b/projects/core/src/site-context/facade/currency.service.ts index f47dcd318fd..ef2972be50d 100644 --- a/projects/core/src/site-context/facade/currency.service.ts +++ b/projects/core/src/site-context/facade/currency.service.ts @@ -3,11 +3,7 @@ import { select, Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { filter, take, tap } from 'rxjs/operators'; import { Currency } from '../../model/misc.model'; -import { WindowRef } from '../../window/window-ref'; -import { - getContextParameterDefault, - getContextParameterValues, -} from '../config/context-config-utils'; +import { getContextParameterValues } from '../config/context-config-utils'; import { SiteContextConfig } from '../config/site-context-config'; import { CURRENCY_CONTEXT_ID } from '../providers/context-ids'; import { SiteContextActions } from '../store/actions/index'; @@ -16,19 +12,14 @@ import { StateWithSiteContext } from '../store/state'; import { SiteContext } from './site-context.interface'; /** - * Facade that provides easy access to curreny state, actions and selectors. + * Facade that provides easy access to currency state, actions and selectors. */ @Injectable() export class CurrencyService implements SiteContext { - private sessionStorage: Storage; - constructor( protected store: Store, - winRef: WindowRef, protected config: SiteContextConfig - ) { - this.sessionStorage = winRef.sessionStorage; - } + ) {} /** * Represents all the currencies supported by the current store. @@ -62,7 +53,7 @@ export class CurrencyService implements SiteContext { this.store .pipe(select(SiteContextSelectors.getActiveCurrency), take(1)) .subscribe((activeCurrency) => { - if (activeCurrency !== isocode) { + if (activeCurrency !== isocode && this.isValid(isocode)) { this.store.dispatch( new SiteContextActions.SetActiveCurrency(isocode) ); @@ -71,33 +62,28 @@ export class CurrencyService implements SiteContext { } /** - * Initials the active currency. The active currency is either given - * by the last visit (stored in session storage) or by the - * default session currency of the store. + * Tells whether the value of the active currency has been already initialized */ - initialize(): void { - let value; + isInitialized(): boolean { + let valueInitialized = false; this.getActive() - .subscribe((val) => (value = val)) + .subscribe(() => (valueInitialized = true)) .unsubscribe(); - if (value) { - // don't initialize, if there is already a value (i.e. retrieved from route or transferred from SSR) - return; - } - const sessionCurrency = - this.sessionStorage && this.sessionStorage.getItem('currency'); - if ( - sessionCurrency && + return valueInitialized; + } + + /** + * Tells whether the given iso code is allowed. + * + * The list of allowed iso codes can be configured in the `context` config of Spartacus. + */ + protected isValid(value: string): boolean { + return ( + !!value && getContextParameterValues(this.config, CURRENCY_CONTEXT_ID).includes( - sessionCurrency + value ) - ) { - this.setActive(sessionCurrency); - } else { - this.setActive( - getContextParameterDefault(this.config, CURRENCY_CONTEXT_ID) - ); - } + ); } } diff --git a/projects/core/src/site-context/facade/language.service.spec.ts b/projects/core/src/site-context/facade/language.service.spec.ts index 1e7af4fd74e..d9adc018ec4 100644 --- a/projects/core/src/site-context/facade/language.service.spec.ts +++ b/projects/core/src/site-context/facade/language.service.spec.ts @@ -97,4 +97,20 @@ describe('LanguageService', () => { ); }); }); + + describe('isInitialized', () => { + it('should return TRUE if a language is initialized', () => { + spyOnProperty(ngrxStore, 'select').and.returnValues(mockSelect1); + expect(service.isInitialized()).toBeTruthy(); + }); + }); + + describe('isValid', () => { + it('should return TRUE if the locale is valid', () => { + expect(service['isValid'](mockActiveLang)).toBeTruthy(); + }); + it('should return FALSE if the locale is not valid', () => { + expect(service['isValid']('zh')).toBeFalsy(); + }); + }); }); diff --git a/projects/core/src/site-context/facade/language.service.ts b/projects/core/src/site-context/facade/language.service.ts index f5d6db8eb5d..a377b0dfcc2 100644 --- a/projects/core/src/site-context/facade/language.service.ts +++ b/projects/core/src/site-context/facade/language.service.ts @@ -3,11 +3,7 @@ import { select, Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { filter, take, tap } from 'rxjs/operators'; import { Language } from '../../model/misc.model'; -import { WindowRef } from '../../window/window-ref'; -import { - getContextParameterDefault, - getContextParameterValues, -} from '../config/context-config-utils'; +import { getContextParameterValues } from '../config/context-config-utils'; import { SiteContextConfig } from '../config/site-context-config'; import { LANGUAGE_CONTEXT_ID } from '../providers/context-ids'; import { SiteContextActions } from '../store/actions/index'; @@ -20,15 +16,10 @@ import { SiteContext } from './site-context.interface'; */ @Injectable() export class LanguageService implements SiteContext { - private sessionStorage: Storage; - constructor( protected store: Store, - winRef: WindowRef, protected config: SiteContextConfig - ) { - this.sessionStorage = winRef.sessionStorage; - } + ) {} /** * Represents all the languages supported by the current store. @@ -62,7 +53,7 @@ export class LanguageService implements SiteContext { this.store .pipe(select(SiteContextSelectors.getActiveLanguage), take(1)) .subscribe((activeLanguage) => { - if (activeLanguage !== isocode) { + if (activeLanguage !== isocode && this.isValid(isocode)) { this.store.dispatch( new SiteContextActions.SetActiveLanguage(isocode) ); @@ -71,33 +62,28 @@ export class LanguageService implements SiteContext { } /** - * Initials the active language. The active language is either given - * by the last visit (stored in session storage) or by the - * default session language of the store. + * Tells whether the value of the active language has been already initialized */ - initialize(): void { - let value; + isInitialized(): boolean { + let valueInitialized = false; this.getActive() - .subscribe((val) => (value = val)) + .subscribe(() => (valueInitialized = true)) .unsubscribe(); - if (value) { - // don't initialize, if there is already a value (i.e. retrieved from route or transferred from SSR) - return; - } - const sessionLanguage = - this.sessionStorage && this.sessionStorage.getItem('language'); - if ( - sessionLanguage && + return valueInitialized; + } + + /** + * Tells whether the given iso code is allowed. + * + * The list of allowed iso codes can be configured in the `context` config of Spartacus. + */ + protected isValid(value: string): boolean { + return ( + !!value && getContextParameterValues(this.config, LANGUAGE_CONTEXT_ID).includes( - sessionLanguage + value ) - ) { - this.setActive(sessionLanguage); - } else { - this.setActive( - getContextParameterDefault(this.config, LANGUAGE_CONTEXT_ID) - ); - } + ); } } diff --git a/projects/core/src/site-context/providers/context-initializer-providers.ts b/projects/core/src/site-context/providers/context-initializer-providers.ts new file mode 100644 index 00000000000..1f971b7d745 --- /dev/null +++ b/projects/core/src/site-context/providers/context-initializer-providers.ts @@ -0,0 +1,45 @@ +import { APP_INITIALIZER, Provider } from '@angular/core'; +import { BaseSiteInitializer } from '../services/base-site-initializer'; +import { CurrencyInitializer } from '../services/currency-initializer'; +import { LanguageInitializer } from '../services/language-initializer'; + +export function initializeCurrency(currencyInitializer: CurrencyInitializer) { + const result = () => { + currencyInitializer.initialize(); + }; + return result; +} +export function initializeLanguage(languageInitializer: LanguageInitializer) { + const result = () => { + languageInitializer.initialize(); + }; + return result; +} + +export function initializeBaseSite(baseSiteInitializer: BaseSiteInitializer) { + const result = () => { + baseSiteInitializer.initialize(); + }; + return result; +} + +export const contextInitializerProviders: Provider[] = [ + { + provide: APP_INITIALIZER, + useFactory: initializeLanguage, + deps: [LanguageInitializer], + multi: true, + }, + { + provide: APP_INITIALIZER, + useFactory: initializeCurrency, + deps: [CurrencyInitializer], + multi: true, + }, + { + provide: APP_INITIALIZER, + useFactory: initializeBaseSite, + deps: [BaseSiteInitializer], + multi: true, + }, +]; diff --git a/projects/core/src/site-context/providers/context-service-providers.ts b/projects/core/src/site-context/providers/context-service-providers.ts index 90f18c39c52..3ccfb0b095a 100644 --- a/projects/core/src/site-context/providers/context-service-providers.ts +++ b/projects/core/src/site-context/providers/context-service-providers.ts @@ -1,4 +1,5 @@ import { APP_INITIALIZER, Provider } from '@angular/core'; +import { tap } from 'rxjs/operators'; import { ConfigInitializerService } from '../../config/config-initializer/config-initializer.service'; import { BaseSiteService } from '../facade/base-site.service'; import { CurrencyService } from '../facade/currency.service'; @@ -6,18 +7,18 @@ import { LanguageService } from '../facade/language.service'; import { SiteContextRoutesHandler } from '../services/site-context-routes-handler'; export function initializeContext( - baseSiteService: BaseSiteService, - langService: LanguageService, - currService: CurrencyService, configInit: ConfigInitializerService, siteContextRoutesHandler: SiteContextRoutesHandler ) { - return async () => { - await configInit.getStableConfig('context'); - siteContextRoutesHandler.init(); - baseSiteService.initialize(); - langService.initialize(); - currService.initialize(); + return () => { + return configInit + .getStable('context') + .pipe( + tap(() => { + siteContextRoutesHandler.init(); + }) + ) + .toPromise(); }; } @@ -28,13 +29,7 @@ export const contextServiceProviders: Provider[] = [ { provide: APP_INITIALIZER, useFactory: initializeContext, - deps: [ - BaseSiteService, - LanguageService, - CurrencyService, - ConfigInitializerService, - SiteContextRoutesHandler, - ], + deps: [ConfigInitializerService, SiteContextRoutesHandler], multi: true, }, ]; diff --git a/projects/core/src/site-context/services/base-site-initializer.spec.ts b/projects/core/src/site-context/services/base-site-initializer.spec.ts new file mode 100644 index 00000000000..00d580e3ded --- /dev/null +++ b/projects/core/src/site-context/services/base-site-initializer.spec.ts @@ -0,0 +1,63 @@ +import { TestBed } from '@angular/core/testing'; +import { of } from 'rxjs'; +import { ConfigInitializerService } from '../../config'; +import { SiteContextConfig } from '../config/site-context-config'; +import { BaseSiteService } from '../facade/base-site.service'; +import { BaseSiteInitializer } from './base-site-initializer'; +import createSpy = jasmine.createSpy; + +const mockSiteContextConfig: SiteContextConfig = { + context: { + baseSite: ['electronics-spa'], + }, +}; + +class MockBaseSiteService implements Partial { + isInitialized() { + return false; + } + setActive = createSpy().and.stub(); +} + +class MockConfigInitializerService + implements Partial { + getStable = () => of(mockSiteContextConfig); +} + +describe('BaseSiteInitializer', () => { + let initializer: BaseSiteInitializer; + let baseSiteService: BaseSiteService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + BaseSiteInitializer, + { provide: BaseSiteService, useClass: MockBaseSiteService }, + { + provide: ConfigInitializerService, + useClass: MockConfigInitializerService, + }, + ], + }); + + baseSiteService = TestBed.inject(BaseSiteService); + initializer = TestBed.inject(BaseSiteInitializer); + }); + + it('should be created', () => { + expect(initializer).toBeTruthy(); + }); + + describe('initialize', () => { + it('should set default from config is the currency is NOT initialized', () => { + initializer.initialize(); + expect(baseSiteService.setActive).toHaveBeenCalledWith('electronics-spa'); + }); + + it('should NOT set default from config is the currency is initialized', () => { + spyOn(baseSiteService, 'isInitialized').and.returnValue(true); + initializer.initialize(); + expect(baseSiteService.setActive).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/projects/core/src/site-context/services/base-site-initializer.ts b/projects/core/src/site-context/services/base-site-initializer.ts new file mode 100644 index 00000000000..43e03bfe4c3 --- /dev/null +++ b/projects/core/src/site-context/services/base-site-initializer.ts @@ -0,0 +1,60 @@ +import { Injectable, OnDestroy } from '@angular/core'; +import { Observable, Subscription } from 'rxjs'; +import { switchMap, tap } from 'rxjs/operators'; +import { ConfigInitializerService } from '../../config/config-initializer/config-initializer.service'; +import { getContextParameterDefault } from '../config/context-config-utils'; +import { SiteContextConfig } from '../config/site-context-config'; +import { BaseSiteService } from '../facade/base-site.service'; +import { BASE_SITE_CONTEXT_ID } from '../providers/context-ids'; + +@Injectable({ providedIn: 'root' }) +export class BaseSiteInitializer implements OnDestroy { + constructor( + protected baseSiteService: BaseSiteService, + protected configInit: ConfigInitializerService + ) {} + + protected subscription: Subscription; + + /** + * Initializes the value of the base site + */ + initialize(): void { + this.subscription = this.configInit + .getStable('context') + .pipe( + // TODO(#12351): <--- plug here explicitly SiteContextRoutesHandler + switchMap(() => this.setFallbackValue()) + ) + .subscribe(); + } + + /** + * On subscription to the returned observable: + * + * Sets the default value taken from config, unless the active base site has been already initialized. + */ + protected setFallbackValue(): Observable { + return this.configInit + .getStable('context') + .pipe( + tap((config: SiteContextConfig) => this.setDefaultFromConfig(config)) + ); + } + + /** + * Sets the active base site value based on the default value from the config, + * unless the active base site has been already initialized. + */ + protected setDefaultFromConfig(config: SiteContextConfig): void { + if (!this.baseSiteService.isInitialized()) { + this.baseSiteService.setActive( + getContextParameterDefault(config, BASE_SITE_CONTEXT_ID) + ); + } + } + + ngOnDestroy() { + this.subscription?.unsubscribe(); + } +} diff --git a/projects/core/src/site-context/services/currency-initializer.spec.ts b/projects/core/src/site-context/services/currency-initializer.spec.ts new file mode 100644 index 00000000000..74e99826012 --- /dev/null +++ b/projects/core/src/site-context/services/currency-initializer.spec.ts @@ -0,0 +1,84 @@ +import { TestBed } from '@angular/core/testing'; +import { EMPTY, of } from 'rxjs'; +import { ConfigInitializerService } from '../../config'; +import { SiteContextConfig } from '../config/site-context-config'; +import { CurrencyService } from '../facade/currency.service'; +import { CurrencyInitializer } from './currency-initializer'; +import { CurrencyStatePersistenceService } from './currency-state-persistence.service'; +import createSpy = jasmine.createSpy; + +const mockSiteContextConfig: SiteContextConfig = { + context: { + currency: ['USD'], + }, +}; + +class MockCurrencyService implements Partial { + isInitialized() { + return false; + } + setActive = createSpy().and.stub(); +} + +class MockCurrencyStatePersistenceService + implements Partial { + initSync = createSpy().and.returnValue(of(EMPTY)); +} + +class MockConfigInitializerService + implements Partial { + getStable = () => of(mockSiteContextConfig); +} + +describe('CurrencyInitializer', () => { + let initializer: CurrencyInitializer; + let currencyService: CurrencyService; + let currencyStatePersistenceService: CurrencyStatePersistenceService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + CurrencyInitializer, + { provide: CurrencyService, useClass: MockCurrencyService }, + { + provide: CurrencyStatePersistenceService, + useClass: MockCurrencyStatePersistenceService, + }, + { + provide: ConfigInitializerService, + useClass: MockConfigInitializerService, + }, + ], + }); + + currencyStatePersistenceService = TestBed.inject( + CurrencyStatePersistenceService + ); + currencyService = TestBed.inject(CurrencyService); + initializer = TestBed.inject(CurrencyInitializer); + }); + + it('should be created', () => { + expect(initializer).toBeTruthy(); + }); + + describe('initialize', () => { + it('should call CurrencyStatePersistenceService initSync()', () => { + spyOn(initializer, 'setFallbackValue').and.returnValue(of(null)); + initializer.initialize(); + expect(currencyStatePersistenceService.initSync).toHaveBeenCalled(); + expect(initializer['setFallbackValue']).toHaveBeenCalled(); + }); + + it('should set default from config is the currency is NOT initialized', () => { + initializer.initialize(); + expect(currencyService.setActive).toHaveBeenCalledWith('USD'); + }); + + it('should NOT set default from config is the currency is initialized', () => { + spyOn(currencyService, 'isInitialized').and.returnValue(true); + initializer.initialize(); + expect(currencyService.setActive).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/projects/core/src/site-context/services/currency-initializer.ts b/projects/core/src/site-context/services/currency-initializer.ts new file mode 100644 index 00000000000..fd1016f327b --- /dev/null +++ b/projects/core/src/site-context/services/currency-initializer.ts @@ -0,0 +1,63 @@ +import { Injectable, OnDestroy } from '@angular/core'; +import { Observable, Subscription } from 'rxjs'; +import { switchMap, tap } from 'rxjs/operators'; +import { ConfigInitializerService } from '../../config'; +import { getContextParameterDefault } from '../config/context-config-utils'; +import { SiteContextConfig } from '../config/site-context-config'; +import { CurrencyService } from '../facade'; +import { CURRENCY_CONTEXT_ID } from '../providers'; +import { CurrencyStatePersistenceService } from './currency-state-persistence.service'; + +@Injectable({ providedIn: 'root' }) +export class CurrencyInitializer implements OnDestroy { + protected subscription: Subscription; + + constructor( + protected currencyService: CurrencyService, + protected currencyStatePersistenceService: CurrencyStatePersistenceService, + protected configInit: ConfigInitializerService + ) {} + + /** + * Initializes the value of the active currency. + */ + initialize(): void { + this.subscription = this.configInit + .getStable('context') + .pipe( + // TODO(#12351): <--- plug here explicitly SiteContextRoutesHandler + switchMap(() => this.currencyStatePersistenceService.initSync()), + switchMap(() => this.setFallbackValue()) + ) + .subscribe(); + } + + /** + * On subscription to the returned observable: + * + * Sets the default value taken from config, unless the active currency has been already initialized. + */ + protected setFallbackValue(): Observable { + return this.configInit + .getStable('context') + .pipe( + tap((config: SiteContextConfig) => this.setDefaultFromConfig(config)) + ); + } + + /** + * Sets the active currency value based on the default value from the config, + * unless the active currency has been already initialized. + */ + protected setDefaultFromConfig(config: SiteContextConfig): void { + if (!this.currencyService.isInitialized()) { + this.currencyService.setActive( + getContextParameterDefault(config, CURRENCY_CONTEXT_ID) + ); + } + } + + ngOnDestroy() { + this.subscription?.unsubscribe(); + } +} diff --git a/projects/core/src/site-context/services/currency-state-persistence.service.spec.ts b/projects/core/src/site-context/services/currency-state-persistence.service.spec.ts new file mode 100644 index 00000000000..58bba5db19c --- /dev/null +++ b/projects/core/src/site-context/services/currency-state-persistence.service.spec.ts @@ -0,0 +1,95 @@ +import { TestBed } from '@angular/core/testing'; +import { of } from 'rxjs'; +import { StatePersistenceService } from '../../state/services/state-persistence.service'; +import { SiteContextConfig } from '../config/site-context-config'; +import { CurrencyService } from '../facade/currency.service'; +import { CURRENCY_CONTEXT_ID } from '../providers'; +import { CurrencyStatePersistenceService } from './currency-state-persistence.service'; +import createSpy = jasmine.createSpy; + +class MockCurrencyService implements Partial { + getActive() { + return of(''); + } + isInitialized() { + return false; + } + setActive = createSpy('setActive'); +} + +const mockCurrencies = ['USD', 'JPY']; + +const mockSiteContextConfig: SiteContextConfig = { + context: { + [CURRENCY_CONTEXT_ID]: mockCurrencies, + }, +}; + +describe('CurrencyStatePersistenceService', () => { + let service: CurrencyStatePersistenceService; + let persistenceService: StatePersistenceService; + let currencyService: CurrencyService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + { + provide: CurrencyService, + useClass: MockCurrencyService, + }, + { provide: SiteContextConfig, useValue: mockSiteContextConfig }, + StatePersistenceService, + ], + }); + + service = TestBed.inject(CurrencyStatePersistenceService); + persistenceService = TestBed.inject(StatePersistenceService); + currencyService = TestBed.inject(CurrencyService); + }); + + it('should inject service', () => { + expect(service).toBeTruthy(); + }); + + describe('initSync', () => { + it('should call StatePersistenceService with the correct attributes', () => { + const state$ = of('USD'); + spyOn(currencyService, 'getActive').and.returnValue(state$); + spyOn(persistenceService, 'syncWithStorage'); + + service.initSync(); + + expect(persistenceService.syncWithStorage).toHaveBeenCalledWith( + jasmine.objectContaining({ + key: CURRENCY_CONTEXT_ID, + state$, + }) + ); + expect(currencyService.getActive).toHaveBeenCalled(); + }); + }); + + describe('onRead', () => { + it('should NOT set active if no value is provided', () => { + spyOn(currencyService, 'isInitialized').and.returnValue(false); + service['onRead'](''); + + expect(currencyService.setActive).not.toHaveBeenCalled(); + }); + it('should NOT set active if the currency is initialized', () => { + spyOn(currencyService, 'isInitialized').and.returnValue(true); + + service['onRead']('CAD'); + + expect(currencyService.setActive).not.toHaveBeenCalled(); + }); + it('should set active value if the currency is NOT initialized and a value is provided', () => { + spyOn(currencyService, 'isInitialized').and.returnValue(false); + const currency = 'CAD'; + + service['onRead'](currency); + + expect(currencyService.setActive).toHaveBeenCalledWith(currency); + }); + }); +}); diff --git a/projects/core/src/site-context/services/currency-state-persistence.service.ts b/projects/core/src/site-context/services/currency-state-persistence.service.ts new file mode 100644 index 00000000000..339597b5ac7 --- /dev/null +++ b/projects/core/src/site-context/services/currency-state-persistence.service.ts @@ -0,0 +1,37 @@ +import { Injectable } from '@angular/core'; +import { Observable, ReplaySubject } from 'rxjs'; +import { StatePersistenceService } from '../../state/services/state-persistence.service'; +import { SiteContextConfig } from '../config/site-context-config'; +import { CurrencyService } from '../facade/currency.service'; +import { CURRENCY_CONTEXT_ID } from '../providers/context-ids'; + +@Injectable({ providedIn: 'root' }) +export class CurrencyStatePersistenceService { + constructor( + protected statePersistenceService: StatePersistenceService, + protected currencyService: CurrencyService, + protected config: SiteContextConfig + ) {} + + protected initialized$ = new ReplaySubject(1); + + public initSync(): Observable { + this.statePersistenceService.syncWithStorage({ + key: CURRENCY_CONTEXT_ID, + state$: this.currencyService.getActive(), + onRead: (state) => this.onRead(state), + }); + return this.initialized$; + } + + protected onRead(valueFromStorage: string): void { + if (!this.currencyService.isInitialized() && valueFromStorage) { + this.currencyService.setActive(valueFromStorage); + } + + if (!this.initialized$.closed) { + this.initialized$.next(); + this.initialized$.complete(); + } + } +} diff --git a/projects/core/src/site-context/services/language-initializer.spec.ts b/projects/core/src/site-context/services/language-initializer.spec.ts new file mode 100644 index 00000000000..64f2b6a56ff --- /dev/null +++ b/projects/core/src/site-context/services/language-initializer.spec.ts @@ -0,0 +1,84 @@ +import { TestBed } from '@angular/core/testing'; +import { EMPTY, of } from 'rxjs'; +import { ConfigInitializerService } from '../../config'; +import { SiteContextConfig } from '../config/site-context-config'; +import { LanguageService } from '../facade/language.service'; +import { LanguageInitializer } from './language-initializer'; +import { LanguageStatePersistenceService } from './language-state-persistence.service'; +import createSpy = jasmine.createSpy; + +const mockSiteContextConfig: SiteContextConfig = { + context: { + language: ['ja'], + }, +}; + +class MockLanguageService implements Partial { + isInitialized() { + return false; + } + setActive = createSpy().and.stub(); +} + +class MockLanguageStatePersistenceService + implements Partial { + initSync = createSpy().and.returnValue(of(EMPTY)); +} + +class MockConfigInitializerService + implements Partial { + getStable = () => of(mockSiteContextConfig); +} + +describe('LanguageInitializer', () => { + let initializer: LanguageInitializer; + let languageService: LanguageService; + let languageStatePersistenceService: LanguageStatePersistenceService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + LanguageInitializer, + { provide: LanguageService, useClass: MockLanguageService }, + { + provide: LanguageStatePersistenceService, + useClass: MockLanguageStatePersistenceService, + }, + { + provide: ConfigInitializerService, + useClass: MockConfigInitializerService, + }, + ], + }); + + languageStatePersistenceService = TestBed.inject( + LanguageStatePersistenceService + ); + languageService = TestBed.inject(LanguageService); + initializer = TestBed.inject(LanguageInitializer); + }); + + it('should be created', () => { + expect(initializer).toBeTruthy(); + }); + + describe('initialize', () => { + it('should call LanguageStatePersistenceService initSync()', () => { + spyOn(initializer, 'setFallbackValue').and.returnValue(of(null)); + initializer.initialize(); + expect(languageStatePersistenceService.initSync).toHaveBeenCalled(); + expect(initializer['setFallbackValue']).toHaveBeenCalled(); + }); + + it('should set default from config is the language is NOT initialized', () => { + initializer.initialize(); + expect(languageService.setActive).toHaveBeenCalledWith('ja'); + }); + + it('should NOT set default from config is the language is initialized', () => { + spyOn(languageService, 'isInitialized').and.returnValue(true); + initializer.initialize(); + expect(languageService.setActive).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/projects/core/src/site-context/services/language-initializer.ts b/projects/core/src/site-context/services/language-initializer.ts new file mode 100644 index 00000000000..7274bc12e5e --- /dev/null +++ b/projects/core/src/site-context/services/language-initializer.ts @@ -0,0 +1,63 @@ +import { Injectable, OnDestroy } from '@angular/core'; +import { Observable, Subscription } from 'rxjs'; +import { switchMap, tap } from 'rxjs/operators'; +import { ConfigInitializerService } from '../../config/config-initializer/config-initializer.service'; +import { getContextParameterDefault } from '../config/context-config-utils'; +import { SiteContextConfig } from '../config/site-context-config'; +import { LanguageService } from '../facade/language.service'; +import { LANGUAGE_CONTEXT_ID } from '../providers/context-ids'; +import { LanguageStatePersistenceService } from './language-state-persistence.service'; + +@Injectable({ providedIn: 'root' }) +export class LanguageInitializer implements OnDestroy { + constructor( + protected languageService: LanguageService, + protected languageStatePersistenceService: LanguageStatePersistenceService, + protected configInit: ConfigInitializerService + ) {} + + protected subscription: Subscription; + + /** + * Initializes the value of the active language. + */ + initialize(): void { + this.subscription = this.configInit + .getStable('context') + .pipe( + // TODO(#12351): <--- plug here explicitly SiteContextRoutesHandler + switchMap(() => this.languageStatePersistenceService.initSync()), + switchMap(() => this.setFallbackValue()) + ) + .subscribe(); + } + + /** + * On subscription to the returned observable: + * + * Sets the default value taken from config, unless the active language has been already initialized. + */ + protected setFallbackValue(): Observable { + return this.configInit + .getStable('context') + .pipe( + tap((config: SiteContextConfig) => this.setDefaultFromConfig(config)) + ); + } + + /** + * Sets the active language value based on the default value from the config, + * unless the active language has been already initialized. + */ + protected setDefaultFromConfig(config: SiteContextConfig): void { + if (!this.languageService.isInitialized()) { + this.languageService.setActive( + getContextParameterDefault(config, LANGUAGE_CONTEXT_ID) + ); + } + } + + ngOnDestroy() { + this.subscription?.unsubscribe(); + } +} diff --git a/projects/core/src/site-context/services/language-state-persistence.service.spec.ts b/projects/core/src/site-context/services/language-state-persistence.service.spec.ts new file mode 100644 index 00000000000..7def471f2b4 --- /dev/null +++ b/projects/core/src/site-context/services/language-state-persistence.service.spec.ts @@ -0,0 +1,95 @@ +import { TestBed } from '@angular/core/testing'; +import { of } from 'rxjs'; +import { StatePersistenceService } from '../../state/services/state-persistence.service'; +import { SiteContextConfig } from '../config/site-context-config'; +import { LanguageService } from '../facade/language.service'; +import { LANGUAGE_CONTEXT_ID } from '../providers'; +import { LanguageStatePersistenceService } from './language-state-persistence.service'; +import createSpy = jasmine.createSpy; + +class MockLanguageService implements Partial { + getActive() { + return of(''); + } + isInitialized() { + return false; + } + setActive = createSpy('setActive'); +} + +const mockLanguages = ['ja', 'de']; + +const mockSiteContextConfig: SiteContextConfig = { + context: { + [LANGUAGE_CONTEXT_ID]: mockLanguages, + }, +}; + +describe('LanguageStatePersistenceService', () => { + let service: LanguageStatePersistenceService; + let persistenceService: StatePersistenceService; + let languageService: LanguageService; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + { + provide: LanguageService, + useClass: MockLanguageService, + }, + { provide: SiteContextConfig, useValue: mockSiteContextConfig }, + StatePersistenceService, + ], + }); + + service = TestBed.inject(LanguageStatePersistenceService); + persistenceService = TestBed.inject(StatePersistenceService); + languageService = TestBed.inject(LanguageService); + }); + + it('should inject service', () => { + expect(service).toBeTruthy(); + }); + + describe('initSync', () => { + it('should call StatePersistenceService with the correct attributes', () => { + const state$ = of('en'); + spyOn(languageService, 'getActive').and.returnValue(state$); + spyOn(persistenceService, 'syncWithStorage'); + + service.initSync(); + + expect(persistenceService.syncWithStorage).toHaveBeenCalledWith( + jasmine.objectContaining({ + key: LANGUAGE_CONTEXT_ID, + state$, + }) + ); + expect(languageService.getActive).toHaveBeenCalled(); + }); + }); + + describe('onRead', () => { + it('should NOT set active if no value is provided', () => { + spyOn(languageService, 'isInitialized').and.returnValue(false); + service['onRead'](''); + + expect(languageService.setActive).not.toHaveBeenCalled(); + }); + it('should NOT set active if the language is initialized', () => { + spyOn(languageService, 'isInitialized').and.returnValue(true); + + service['onRead']('ja'); + + expect(languageService.setActive).not.toHaveBeenCalled(); + }); + it('should set active value if the currency is NOT initialized and a value is provided', () => { + spyOn(languageService, 'isInitialized').and.returnValue(false); + const language = 'ja'; + + service['onRead'](language); + + expect(languageService.setActive).toHaveBeenCalledWith(language); + }); + }); +}); diff --git a/projects/core/src/site-context/services/language-state-persistence.service.ts b/projects/core/src/site-context/services/language-state-persistence.service.ts new file mode 100644 index 00000000000..789ebeab7a4 --- /dev/null +++ b/projects/core/src/site-context/services/language-state-persistence.service.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@angular/core'; +import { Observable, ReplaySubject } from 'rxjs'; +import { StatePersistenceService } from '../../state/services/state-persistence.service'; +import { SiteContextConfig } from '../config/site-context-config'; +import { LanguageService } from '../facade/language.service'; +import { LANGUAGE_CONTEXT_ID } from '../providers/context-ids'; + +@Injectable({ providedIn: 'root' }) +export class LanguageStatePersistenceService { + constructor( + protected statePersistenceService: StatePersistenceService, + protected languageService: LanguageService, + protected config: SiteContextConfig + ) {} + + protected initialized$ = new ReplaySubject(1); + + /** + * Initializes the synchronization of the active language with the local storage. + * + * @returns Observable that emits and completes when the value is read from the storage. + */ + public initSync(): Observable { + this.statePersistenceService.syncWithStorage({ + key: LANGUAGE_CONTEXT_ID, + state$: this.languageService.getActive(), + onRead: (state) => this.onRead(state), + }); + return this.initialized$; + } + + protected onRead(valueFromStorage: string): void { + if (!this.languageService.isInitialized() && valueFromStorage) { + this.languageService.setActive(valueFromStorage); + } + + if (!this.initialized$.closed) { + this.initialized$.next(); + this.initialized$.complete(); + } + } +} diff --git a/projects/core/src/site-context/site-context.module.ts b/projects/core/src/site-context/site-context.module.ts index 8579cc294a2..379f7df8ff2 100644 --- a/projects/core/src/site-context/site-context.module.ts +++ b/projects/core/src/site-context/site-context.module.ts @@ -13,6 +13,7 @@ import { defaultSiteContextConfigFactory } from './config/default-site-context-c import { SiteContextConfig } from './config/site-context-config'; import { SiteContextEventModule } from './events/site-context-event.module'; import { BASE_SITE_CONTEXT_ID } from './providers/context-ids'; +import { contextInitializerProviders } from './providers/context-initializer-providers'; import { contextServiceMapProvider } from './providers/context-service-map'; import { contextServiceProviders } from './providers/context-service-providers'; import { siteContextParamsProviders } from './providers/site-context-params-providers'; @@ -62,6 +63,7 @@ export class SiteContextModule { ], multi: true, }, + ...contextInitializerProviders, ], }; } diff --git a/projects/core/src/site-context/store/effects/currencies.effect.spec.ts b/projects/core/src/site-context/store/effects/currencies.effect.spec.ts index b22fd73953e..59923eae4c7 100644 --- a/projects/core/src/site-context/store/effects/currencies.effect.spec.ts +++ b/projects/core/src/site-context/store/effects/currencies.effect.spec.ts @@ -3,11 +3,9 @@ import { TestBed } from '@angular/core/testing'; import { provideMockActions } from '@ngrx/effects/testing'; import { Store } from '@ngrx/store'; import { BehaviorSubject, of, Subject } from 'rxjs'; -import { take } from 'rxjs/operators'; import { ConfigModule } from '../../../config/config.module'; import { Currency } from '../../../model/misc.model'; import { OccModule } from '../../../occ/occ.module'; -import { WindowRef } from '../../../window'; import { SiteAdapter } from '../../connectors/site.adapter'; import { SiteConnector } from '../../connectors/site.connector'; import { SiteContextActions } from '../actions/index'; @@ -15,7 +13,6 @@ import * as fromEffects from './currencies.effect'; describe('Currencies Effects', () => { let actions$: Subject; - let winRef: WindowRef; let connector: SiteConnector; let effects: fromEffects.CurrenciesEffects; let mockState: BehaviorSubject; @@ -37,20 +34,11 @@ describe('Currencies Effects', () => { { provide: SiteAdapter, useValue: {} }, provideMockActions(() => actions$), { provide: Store, useValue: mockStore }, - { - provide: WindowRef, - useValue: { - sessionStorage: { - setItem: jasmine.createSpy('sessionStorage.setItem'), - }, - }, - }, ], }); connector = TestBed.inject(SiteConnector); effects = TestBed.inject(fromEffects.CurrenciesEffects); - winRef = TestBed.inject(WindowRef); spyOn(connector, 'getCurrencies').and.returnValue(of(currencies)); }); @@ -92,18 +80,4 @@ describe('Currencies Effects', () => { }); }); }); - - describe('persist$', () => { - describe('when new value is set for active currency', () => { - it('should persist it in the session storage', () => { - effects.persist$.pipe(take(1)).subscribe(); - actions$.next(new SiteContextActions.SetActiveCurrency('en')); - - expect(winRef.sessionStorage.setItem).toHaveBeenCalledWith( - 'currency', - 'en' - ); - }); - }); - }); }); diff --git a/projects/core/src/site-context/store/effects/currencies.effect.ts b/projects/core/src/site-context/store/effects/currencies.effect.ts index 79d5b79b4b2..acbf44ac933 100644 --- a/projects/core/src/site-context/store/effects/currencies.effect.ts +++ b/projects/core/src/site-context/store/effects/currencies.effect.ts @@ -1,18 +1,15 @@ import { Injectable } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; -import { NEVER, Observable, of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { bufferCount, catchError, exhaustMap, filter, map, - switchMapTo, - tap, } from 'rxjs/operators'; import { normalizeHttpError } from '../../../util/normalize-http-error'; -import { WindowRef } from '../../../window/window-ref'; import { SiteConnector } from '../../connectors/site.connector'; import { SiteContextActions } from '../actions/index'; import { getActiveCurrency } from '../selectors/currencies.selectors'; @@ -41,17 +38,6 @@ export class CurrenciesEffects { }) ); - @Effect() - persist$: Observable = this.actions$.pipe( - ofType(SiteContextActions.SET_ACTIVE_CURRENCY), - tap((action: SiteContextActions.SetActiveCurrency) => { - if (this.winRef.sessionStorage) { - this.winRef.sessionStorage.setItem('currency', action.payload); - } - }), - switchMapTo(NEVER) - ); - @Effect() activateCurrency$: Observable = this.state .select(getActiveCurrency) @@ -69,7 +55,6 @@ export class CurrenciesEffects { constructor( private actions$: Actions, private siteConnector: SiteConnector, - private winRef: WindowRef, private state: Store ) {} } diff --git a/projects/core/src/site-context/store/effects/languages.effect.spec.ts b/projects/core/src/site-context/store/effects/languages.effect.spec.ts index 64e3f35d80f..c92a5f3dcb3 100644 --- a/projects/core/src/site-context/store/effects/languages.effect.spec.ts +++ b/projects/core/src/site-context/store/effects/languages.effect.spec.ts @@ -3,11 +3,9 @@ import { TestBed } from '@angular/core/testing'; import { provideMockActions } from '@ngrx/effects/testing'; import { Store } from '@ngrx/store'; import { BehaviorSubject, of, Subject } from 'rxjs'; -import { take } from 'rxjs/operators'; import { ConfigModule } from '../../../config/config.module'; import { Language } from '../../../model/misc.model'; import { OccModule } from '../../../occ/occ.module'; -import { WindowRef } from '../../../window'; import { SiteAdapter } from '../../connectors/site.adapter'; import { SiteConnector } from '../../connectors/site.connector'; import { SiteContextActions } from '../actions/index'; @@ -15,7 +13,6 @@ import * as fromEffects from './languages.effect'; describe('Languages Effects', () => { let actions$: Subject; - let winRef: WindowRef; let connector: SiteConnector; let effects: fromEffects.LanguagesEffects; let mockState: BehaviorSubject; @@ -37,20 +34,11 @@ describe('Languages Effects', () => { { provide: SiteAdapter, useValue: {} }, provideMockActions(() => actions$), { provide: Store, useValue: mockStore }, - { - provide: WindowRef, - useValue: { - sessionStorage: { - setItem: jasmine.createSpy('sessionStorage.setItem'), - }, - }, - }, ], }); connector = TestBed.inject(SiteConnector); effects = TestBed.inject(fromEffects.LanguagesEffects); - winRef = TestBed.inject(WindowRef); spyOn(connector, 'getLanguages').and.returnValue(of(languages)); }); @@ -92,18 +80,4 @@ describe('Languages Effects', () => { }); }); }); - - describe('persist$', () => { - describe('when new value is set for active currency', () => { - it('should persist it in the session storage', () => { - effects.persist$.pipe(take(1)).subscribe(); - actions$.next(new SiteContextActions.SetActiveLanguage('en')); - - expect(winRef.sessionStorage.setItem).toHaveBeenCalledWith( - 'language', - 'en' - ); - }); - }); - }); }); diff --git a/projects/core/src/site-context/store/effects/languages.effect.ts b/projects/core/src/site-context/store/effects/languages.effect.ts index 2f8e7da5d2c..d41049aa82b 100644 --- a/projects/core/src/site-context/store/effects/languages.effect.ts +++ b/projects/core/src/site-context/store/effects/languages.effect.ts @@ -1,18 +1,15 @@ import { Injectable } from '@angular/core'; import { Actions, Effect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; -import { NEVER, Observable, of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { bufferCount, catchError, exhaustMap, filter, map, - switchMapTo, - tap, } from 'rxjs/operators'; import { normalizeHttpError } from '../../../util/normalize-http-error'; -import { WindowRef } from '../../../window/window-ref'; import { SiteConnector } from '../../connectors/site.connector'; import { SiteContextActions } from '../actions/index'; import { getActiveLanguage } from '../selectors/languages.selectors'; @@ -40,17 +37,6 @@ export class LanguagesEffects { }) ); - @Effect() - persist$: Observable = this.actions$.pipe( - ofType(SiteContextActions.SET_ACTIVE_LANGUAGE), - tap((action: SiteContextActions.SetActiveLanguage) => { - if (this.winRef.sessionStorage) { - this.winRef.sessionStorage.setItem('language', action.payload); - } - }), - switchMapTo(NEVER) - ); - @Effect() activateLanguage$: Observable = this.state .select(getActiveLanguage) @@ -68,7 +54,6 @@ export class LanguagesEffects { constructor( private actions$: Actions, private siteConnector: SiteConnector, - private winRef: WindowRef, private state: Store ) {} } diff --git a/projects/core/src/window/window-ref.spec.ts b/projects/core/src/window/window-ref.spec.ts index 2b1481c98a4..785c1cbf2e8 100644 --- a/projects/core/src/window/window-ref.spec.ts +++ b/projects/core/src/window/window-ref.spec.ts @@ -69,23 +69,4 @@ describe('WindowRef service', () => { expect(service.localStorage).toEqual(localStorage); }); }); - - describe('when platform is not defined', () => { - let service: WindowRef; - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [{ provide: PLATFORM_ID, useValue: undefined }], - }); - service = TestBed.inject(WindowRef); - }); - - it('isBrowser should return true when window exists', () => { - expect(window).toBeDefined(); - expect(service.isBrowser()).toEqual(true); - }); - - it('should expose window as nativeWindow', () => { - expect(service.nativeWindow).toEqual(window); - }); - }); }); diff --git a/projects/core/src/window/window-ref.ts b/projects/core/src/window/window-ref.ts index 7da812a655a..90979df6c13 100644 --- a/projects/core/src/window/window-ref.ts +++ b/projects/core/src/window/window-ref.ts @@ -10,14 +10,10 @@ import { SERVER_REQUEST_ORIGIN, SERVER_REQUEST_URL } from '../util/ssr.tokens'; export class WindowRef { readonly document: Document; - // TODO(#11133): Make platformId required in 4.0 - /** - * @deprecated since 3.2. Provide PLATFORM_ID, serverRequestUrl and serverRequestOrigin as constructor parameters - */ constructor( // https://github.com/angular/angular/issues/20351 @Inject(DOCUMENT) document: any, - @Inject(PLATFORM_ID) protected platformId?: Object, + @Inject(PLATFORM_ID) protected platformId: Object, @Optional() @Inject(SERVER_REQUEST_URL) protected serverUrl?: string, @Optional() @Inject(SERVER_REQUEST_ORIGIN) protected serverOrigin?: string ) { @@ -29,10 +25,7 @@ export class WindowRef { * Use this method to check if you can access `window` and other browser globals. */ isBrowser(): boolean { - // TODO(#11133): Remove condition when platformId will be always provided - return this.platformId - ? isPlatformBrowser(this.platformId) - : typeof window !== 'undefined'; + return isPlatformBrowser(this.platformId); } /** diff --git a/projects/schematics/src/add-cms-component/index_spec.ts b/projects/schematics/src/add-cms-component/index_spec.ts index 6caa906f06b..c5921303652 100644 --- a/projects/schematics/src/add-cms-component/index_spec.ts +++ b/projects/schematics/src/add-cms-component/index_spec.ts @@ -101,7 +101,6 @@ describe('add-cms-component', () => { project: 'schematics-test', baseSite: 'electronics', baseUrl: 'https://localhost:9002', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/projects/schematics/src/add-pwa/index_spec.ts b/projects/schematics/src/add-pwa/index_spec.ts index 00e093a3076..28d34282daa 100644 --- a/projects/schematics/src/add-pwa/index_spec.ts +++ b/projects/schematics/src/add-pwa/index_spec.ts @@ -34,7 +34,6 @@ describe('Spartacus Schematics: add-pwa', () => { const defaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/projects/schematics/src/add-spartacus/configuration.ts b/projects/schematics/src/add-spartacus/configuration.ts index 1a03fcaf0fc..bd6a139bde6 100644 --- a/projects/schematics/src/add-spartacus/configuration.ts +++ b/projects/schematics/src/add-spartacus/configuration.ts @@ -11,7 +11,6 @@ import { SPARTACUS_CORE, SPARTACUS_STOREFRONTLIB, } from '../shared/constants'; -import { getB2bConfiguration } from '../shared/utils/config-utils'; import { addModuleProvider } from '../shared/utils/new-module-utils'; import { getSpartacusCurrentFeatureLevel } from '../shared/utils/package-utils'; import { createProgram, saveAndFormat } from '../shared/utils/program'; @@ -52,11 +51,6 @@ function addConfiguration( .includes(`${SPARTACUS_CONFIGURATION_MODULE}.module.ts`) ) { addCommonConfiguration(sourceFile, options); - if (options.configuration === 'b2b') { - getB2bConfiguration().forEach((b2bProvider) => - addModuleProvider(sourceFile, b2bProvider) - ); - } saveAndFormat(sourceFile); diff --git a/projects/schematics/src/add-spartacus/index.ts b/projects/schematics/src/add-spartacus/index.ts index 5953eca56e4..8bb8b3a6a9d 100644 --- a/projects/schematics/src/add-spartacus/index.ts +++ b/projects/schematics/src/add-spartacus/index.ts @@ -164,12 +164,8 @@ function updateIndexFile(tree: Tree, options: SpartacusOptions): Rule { }; } -export function prepareDependencies( - options: SpartacusOptions -): NodeDependency[] { - const spartacusDependencies = prepareSpartacusDependencies( - options.configuration === 'b2b' - ); +export function prepareDependencies(): NodeDependency[] { + const spartacusDependencies = prepareSpartacusDependencies(); return spartacusDependencies.concat(prepare3rdPartyDependencies()); } @@ -235,7 +231,7 @@ export function addSpartacus(options: SpartacusOptions): Rule { const project = getProjectFromWorkspace(tree, options); return chain([ - addPackageJsonDependencies(prepareDependencies(options)), + addPackageJsonDependencies(prepareDependencies()), ensureModuleExists({ name: SPARTACUS_ROUTING_MODULE, path: 'app', diff --git a/projects/schematics/src/add-spartacus/index_spec.ts b/projects/schematics/src/add-spartacus/index_spec.ts index 8c509fabc75..b694d400e33 100644 --- a/projects/schematics/src/add-spartacus/index_spec.ts +++ b/projects/schematics/src/add-spartacus/index_spec.ts @@ -43,7 +43,6 @@ describe('add-spartacus', () => { occPrefix: 'xxx', baseSite: 'electronics', baseUrl: 'https://localhost:9002', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/projects/schematics/src/add-spartacus/schema.json b/projects/schematics/src/add-spartacus/schema.json index ab91e765750..eaa1f091793 100644 --- a/projects/schematics/src/add-spartacus/schema.json +++ b/projects/schematics/src/add-spartacus/schema.json @@ -11,17 +11,6 @@ "$source": "projectName" } }, - "configuration": { - "description": "The Spartacus configuration to use in the application.", - "type": "string", - "default": "b2c", - "enum": ["b2c", "b2b"], - "x-prompt": { - "message": "Please choose which configuration you would like to add.", - "type": "list", - "items": ["b2c", "b2b"] - } - }, "features": { "type": "array", "uniqueItems": true, @@ -48,7 +37,17 @@ ], "type": "string" }, - "default": ["Account", "Profile"], + "default": [ + "ASM", + "Saved-Cart", + "Bulk-Pricing", + "Product-Variants", + "SmartEdit", + "Store-Finder", + "Personalization", + "Account", + "Profile" + ], "x-prompt": { "message": "Which Spartacus features would you like to set up?\nPlease note that for most Spartacus features to be properly configured, the Account feature is required.", "type": "list", diff --git a/projects/schematics/src/add-spartacus/schema.ts b/projects/schematics/src/add-spartacus/schema.ts index 3b08c16e731..14aeb670c27 100644 --- a/projects/schematics/src/add-spartacus/schema.ts +++ b/projects/schematics/src/add-spartacus/schema.ts @@ -1,7 +1,6 @@ import { LibraryOptions } from '../shared/utils/lib-utils'; export interface Schema extends LibraryOptions { - configuration: 'b2c' | 'b2b'; baseUrl?: string; occPrefix?: string; baseSite?: string; diff --git a/projects/schematics/src/add-ssr/index_spec.ts b/projects/schematics/src/add-ssr/index_spec.ts index dedb9cfb84f..2fc2dd96408 100644 --- a/projects/schematics/src/add-ssr/index_spec.ts +++ b/projects/schematics/src/add-ssr/index_spec.ts @@ -38,7 +38,6 @@ describe('add-ssr', () => { project: 'schematics-test', baseSite: 'electronics', baseUrl: 'https://localhost:9002', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/constructor-deprecations.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/constructor-deprecations.ts index ced2aa23a93..49012ef0616 100644 --- a/projects/schematics/src/migrations/4_0/constructor-deprecations/constructor-deprecations.ts +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/constructor-deprecations.ts @@ -11,12 +11,43 @@ import { CONFIGURATOR_ATTRIBUTE_DROP_DOWN_COMPONENT_MIGRATION } from './data/con import { CONFIGURATOR_ATTRIBUTE_RADIO_BUTTON_COMPONENT_MIGRATION } from './data/configurator-attribute-radio-button.component.migration'; import { CONFIGURATOR_CART_ENTRY_INFO_COMPONENT_MIGRATION } from './data/configurator-cart-entry-info.component.migration'; import { CONFIGURATOR_STOREFRONT_UTILS_SERVICE_MIGRATION } from './data/configurator-storefront-utils.service.migration'; +import { CURRENCY_SERVICE_MIGRATION } from './data/currency.service.migration'; import { HOME_PAGE_EVENT_BUILDER_COMPONENT_MIGRATION } from './data/home-page-event.builder.migration'; +import { LANGUAGE_SERVICE_MIGRATION } from './data/language.service.migration'; import { PRODUCT_PAGE_EVENT_BUILDER_COMPONENT_MIGRATION } from './data/product-page-event.builder.migration'; import { SEARCH_BOX_COMPONENT_SERVICE_MIGRATION } from './data/search-box-component.service.migration'; import { UNIT_CHILDREN_COMPONENT_MIGRATION } from './data/unit-children.component.migration'; import { UNIT_COST_CENTERS_COMPONENT_MIGRATION } from './data/unit-cost-centers.component.migration'; import { UNIT_USER_LIST_COMPONENT_MIGRATION } from './data/unit-user-list.component.migration'; +import { + ADD_TO_SAVED_CART_COMPONENT_MIGRATION_V1, + ADD_TO_SAVED_CART_COMPONENT_MIGRATION_V2, +} from './data/add-to-saved-cart.component.migration'; +import { + ANONYMOUS_CONSENT_MANAGEMENT_BANNER_COMPONENT_MIGRATION_V1, + ANONYMOUS_CONSENT_MANAGEMENT_BANNER_COMPONENT_MIGRATION_V2, +} from './data/anonymous-consent-management-banner.component.migration'; +import { + ANONYMOUS_CONSENT_OPEN_DIALOG_COMPONENT_MIGRATION_V1, + ANONYMOUS_CONSENT_OPEN_DIALOG_COMPONENT_MIGRATION_V2, +} from './data/anonymous-consent-open-dialog.component.migration'; +import { + REPLENISHMENT_ORDER_CANCELLATION_COMPONENT_MIGRATION_V1, + REPLENISHMENT_ORDER_CANCELLATION_COMPONENT_MIGRATION_V2, +} from './data/replenishment-order-cancellation.component.migration'; +import { + REPLENISHMENT_ORDER_HISTORY_COMPONENT_MIGRATION_V1, + REPLENISHMENT_ORDER_HISTORY_COMPONENT_MIGRATION_V2, +} from './data/replenishment-order-history.component.migration'; +import { + SAVED_CART_DETAILS_ACTION_COMPONENT_MIGRATION_V1, + SAVED_CART_DETAILS_ACTION_COMPONENT_MIGRATION_V2, +} from './data/saved-cart-details-action.component.migration'; +import { + SAVED_CART_DETAILS_OVERVIEW_COMPONENT_MIGRATION_V1, + SAVED_CART_DETAILS_OVERVIEW_COMPONENT_MIGRATION_V2, +} from './data/saved-cart-details-overview.component.migration'; +import { WINDOW_REF_MIGRATION } from './data/window-ref.migration'; export const CONSTRUCTOR_DEPRECATION_DATA: ConstructorDeprecation[] = [ UNIT_CHILDREN_COMPONENT_MIGRATION, @@ -27,7 +58,24 @@ export const CONSTRUCTOR_DEPRECATION_DATA: ConstructorDeprecation[] = [ HOME_PAGE_EVENT_BUILDER_COMPONENT_MIGRATION, PRODUCT_PAGE_EVENT_BUILDER_COMPONENT_MIGRATION, SEARCH_BOX_COMPONENT_SERVICE_MIGRATION, + CURRENCY_SERVICE_MIGRATION, + LANGUAGE_SERVICE_MIGRATION, COMPONENT_WRAPPER_CONSTRUCTOR_MIGRATION, + ADD_TO_SAVED_CART_COMPONENT_MIGRATION_V1, + ADD_TO_SAVED_CART_COMPONENT_MIGRATION_V2, + ANONYMOUS_CONSENT_MANAGEMENT_BANNER_COMPONENT_MIGRATION_V1, + ANONYMOUS_CONSENT_MANAGEMENT_BANNER_COMPONENT_MIGRATION_V2, + ANONYMOUS_CONSENT_OPEN_DIALOG_COMPONENT_MIGRATION_V1, + ANONYMOUS_CONSENT_OPEN_DIALOG_COMPONENT_MIGRATION_V2, + REPLENISHMENT_ORDER_CANCELLATION_COMPONENT_MIGRATION_V1, + REPLENISHMENT_ORDER_CANCELLATION_COMPONENT_MIGRATION_V2, + REPLENISHMENT_ORDER_HISTORY_COMPONENT_MIGRATION_V1, + REPLENISHMENT_ORDER_HISTORY_COMPONENT_MIGRATION_V2, + SAVED_CART_DETAILS_ACTION_COMPONENT_MIGRATION_V1, + SAVED_CART_DETAILS_ACTION_COMPONENT_MIGRATION_V2, + SAVED_CART_DETAILS_OVERVIEW_COMPONENT_MIGRATION_V1, + SAVED_CART_DETAILS_OVERVIEW_COMPONENT_MIGRATION_V2, + WINDOW_REF_MIGRATION, CONFIGURATOR_CART_ENTRY_INFO_COMPONENT_MIGRATION, CONFIGURATOR_ATTRIBUTE_CHECKBOX_LIST_COMPONENT_MIGRATION, CONFIGURATOR_ATTRIBUTE_DROP_DOWN_COMPONENT_MIGRATION, diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/add-to-saved-cart.component.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/add-to-saved-cart.component.migration.ts new file mode 100644 index 00000000000..822d62277d5 --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/add-to-saved-cart.component.migration.ts @@ -0,0 +1,92 @@ +import { + ACTIVE_CART_SERVICE, + ADD_TO_SAVED_CART_COMPONENT, + ANGULAR_CORE, + AUTH_SERVICE, + LAUNCH_DIALOG_SERVICE, + ROUTING_SERVICE, + SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + SPARTACUS_CART_SAVED_CART_COMPONENTS, + SPARTACUS_CORE, + SPARTACUS_STOREFRONTLIB, + VIEW_CONTAINER_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const ADD_TO_SAVED_CART_COMPONENT_MIGRATION_V1: ConstructorDeprecation = { + // feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.ts + class: ADD_TO_SAVED_CART_COMPONENT, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + deprecatedParams: [ + { + className: ACTIVE_CART_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: AUTH_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: ROUTING_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + ], + removeParams: [ + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + ], + addParams: [ + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; + +export const ADD_TO_SAVED_CART_COMPONENT_MIGRATION_V2: ConstructorDeprecation = { + // feature-libs/cart/saved-cart/components/add-to-saved-cart/add-to-saved-cart.component.ts + class: ADD_TO_SAVED_CART_COMPONENT, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + deprecatedParams: [ + { + className: ACTIVE_CART_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: AUTH_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: ROUTING_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + removeParams: [ + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + ], +}; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/anonymous-consent-management-banner.component.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/anonymous-consent-management-banner.component.migration.ts new file mode 100644 index 00000000000..d4ac40f5a14 --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/anonymous-consent-management-banner.component.migration.ts @@ -0,0 +1,73 @@ +import { + ANGULAR_CORE, + ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + ANONYMOUS_CONSENT_MANAGEMENT_BANNER_COMPONENT, + ANONYMOUS_CONSENTS_SERVICE, + LAUNCH_DIALOG_SERVICE, + SPARTACUS_CORE, + SPARTACUS_STOREFRONTLIB, + VIEW_CONTAINER_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const ANONYMOUS_CONSENT_MANAGEMENT_BANNER_COMPONENT_MIGRATION_V1: ConstructorDeprecation = { + // storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.ts + class: ANONYMOUS_CONSENT_MANAGEMENT_BANNER_COMPONENT, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { + className: ANONYMOUS_CONSENTS_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + ], + removeParams: [ + { + className: ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + addParams: [ + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; + +export const ANONYMOUS_CONSENT_MANAGEMENT_BANNER_COMPONENT_MIGRATION_V2: ConstructorDeprecation = { + // storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.ts + class: ANONYMOUS_CONSENT_MANAGEMENT_BANNER_COMPONENT, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { + className: ANONYMOUS_CONSENTS_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + removeParams: [ + { + className: ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/anonymous-consent-open-dialog.component.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/anonymous-consent-open-dialog.component.migration.ts new file mode 100644 index 00000000000..9ffc935d8bb --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/anonymous-consent-open-dialog.component.migration.ts @@ -0,0 +1,63 @@ +import { + ANGULAR_CORE, + ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + ANONYMOUS_CONSENT_OPEN_DIALOG_COMPONENT, + LAUNCH_DIALOG_SERVICE, + SPARTACUS_STOREFRONTLIB, + VIEW_CONTAINER_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const ANONYMOUS_CONSENT_OPEN_DIALOG_COMPONENT_MIGRATION_V1: ConstructorDeprecation = { + // storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.ts + class: ANONYMOUS_CONSENT_OPEN_DIALOG_COMPONENT, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + { + className: ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + removeParams: [ + { + className: ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + addParams: [ + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; + +export const ANONYMOUS_CONSENT_OPEN_DIALOG_COMPONENT_MIGRATION_V2: ConstructorDeprecation = { + // storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.ts + class: ANONYMOUS_CONSENT_OPEN_DIALOG_COMPONENT, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + { + className: ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + removeParams: [ + { + className: ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/currency.service.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/currency.service.migration.ts new file mode 100644 index 00000000000..e96353fd5f9 --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/currency.service.migration.ts @@ -0,0 +1,22 @@ +import { + CURRENCY_SERVICE, + NGRX_STORE, + SITE_CONTEXT_CONFIG, + SPARTACUS_CORE, + SPARTACUS_STOREFRONTLIB, + STORE, + WINDOW_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const CURRENCY_SERVICE_MIGRATION: ConstructorDeprecation = { + // projects/core/src/site-context/facade/currency.service.ts + class: CURRENCY_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { className: STORE, importPath: NGRX_STORE }, + { className: WINDOW_REF, importPath: SPARTACUS_CORE }, + { className: SITE_CONTEXT_CONFIG, importPath: SPARTACUS_CORE }, + ], + removeParams: [{ className: WINDOW_REF, importPath: SPARTACUS_CORE }], +}; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/language.service.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/language.service.migration.ts new file mode 100644 index 00000000000..e3f18bf9806 --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/language.service.migration.ts @@ -0,0 +1,22 @@ +import { + LANGUAGE_SERVICE, + NGRX_STORE, + SITE_CONTEXT_CONFIG, + SPARTACUS_CORE, + SPARTACUS_STOREFRONTLIB, + STORE, + WINDOW_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const LANGUAGE_SERVICE_MIGRATION: ConstructorDeprecation = { + // projects/core/src/site-context/facade/language.service.ts + class: LANGUAGE_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { className: STORE, importPath: NGRX_STORE }, + { className: WINDOW_REF, importPath: SPARTACUS_CORE }, + { className: SITE_CONTEXT_CONFIG, importPath: SPARTACUS_CORE }, + ], + removeParams: [{ className: WINDOW_REF, importPath: SPARTACUS_CORE }], +}; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/replenishment-order-cancellation.component.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/replenishment-order-cancellation.component.migration.ts new file mode 100644 index 00000000000..00048c30a8e --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/replenishment-order-cancellation.component.migration.ts @@ -0,0 +1,73 @@ +import { + ANGULAR_CORE, + LAUNCH_DIALOG_SERVICE, + REPLENISHMENT_ORDER_CANCELLATION_COMPONENT, + REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + SPARTACUS_CORE, + SPARTACUS_STOREFRONTLIB, + USER_REPLENISHMENT_ORDER_SERVICE, + VIEW_CONTAINER_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const REPLENISHMENT_ORDER_CANCELLATION_COMPONENT_MIGRATION_V1: ConstructorDeprecation = { + // storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.ts + class: REPLENISHMENT_ORDER_CANCELLATION_COMPONENT, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { + className: USER_REPLENISHMENT_ORDER_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + ], + removeParams: [ + { + className: REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + addParams: [ + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; + +export const REPLENISHMENT_ORDER_CANCELLATION_COMPONENT_MIGRATION_V2: ConstructorDeprecation = { + // storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.ts + class: REPLENISHMENT_ORDER_CANCELLATION_COMPONENT, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { + className: USER_REPLENISHMENT_ORDER_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + removeParams: [ + { + className: REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/replenishment-order-history.component.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/replenishment-order-history.component.migration.ts new file mode 100644 index 00000000000..cf1b1c2f61e --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/replenishment-order-history.component.migration.ts @@ -0,0 +1,91 @@ +import { + ANGULAR_CORE, + LAUNCH_DIALOG_SERVICE, + REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + REPLENISHMENT_ORDER_HISTORY_COMPONENT, + ROUTING_SERVICE, + SPARTACUS_CORE, + SPARTACUS_STOREFRONTLIB, + TRANSLATION_SERVICE, + USER_REPLENISHMENT_ORDER_SERVICE, + VIEW_CONTAINER_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const REPLENISHMENT_ORDER_HISTORY_COMPONENT_MIGRATION_V1: ConstructorDeprecation = { + // storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.ts + class: REPLENISHMENT_ORDER_HISTORY_COMPONENT, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { + className: ROUTING_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: USER_REPLENISHMENT_ORDER_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + { + className: TRANSLATION_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + ], + removeParams: [ + { + className: REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + addParams: [ + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; + +export const REPLENISHMENT_ORDER_HISTORY_COMPONENT_MIGRATION_V2: ConstructorDeprecation = { + // storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.ts + class: REPLENISHMENT_ORDER_HISTORY_COMPONENT, + importPath: SPARTACUS_STOREFRONTLIB, + deprecatedParams: [ + { + className: ROUTING_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: USER_REPLENISHMENT_ORDER_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + { + className: TRANSLATION_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + removeParams: [ + { + className: REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/saved-cart-details-action.component.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/saved-cart-details-action.component.migration.ts new file mode 100644 index 00000000000..b7622219cf2 --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/saved-cart-details-action.component.migration.ts @@ -0,0 +1,111 @@ +import { + ANGULAR_CORE, + CLEAR_CHECKOUT_SERVICE, + GLOBAL_MESSAGE_SERVICE, + LAUNCH_DIALOG_SERVICE, + ROUTING_SERVICE, + SAVED_CART_DETAILS_ACTION_COMPONENT, + SAVED_CART_DETAILS_SERVICE, + SAVED_CART_FACADE, + SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + SPARTACUS_CART_SAVED_CART_COMPONENTS, + SPARTACUS_CART_SAVED_CART_ROOT, + SPARTACUS_CORE, + SPARTACUS_STOREFRONTLIB, + VIEW_CONTAINER_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const SAVED_CART_DETAILS_ACTION_COMPONENT_MIGRATION_V1: ConstructorDeprecation = { + // feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.ts + class: SAVED_CART_DETAILS_ACTION_COMPONENT, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + deprecatedParams: [ + { + className: SAVED_CART_DETAILS_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: SAVED_CART_FACADE, + importPath: SPARTACUS_CART_SAVED_CART_ROOT, + }, + { + className: ROUTING_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: GLOBAL_MESSAGE_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + { + className: CLEAR_CHECKOUT_SERVICE, + importPath: SPARTACUS_CORE, + }, + ], + removeParams: [ + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + ], + addParams: [ + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; + +export const SAVED_CART_DETAILS_ACTION_COMPONENT_MIGRATION_V2: ConstructorDeprecation = { + // feature-libs/cart/saved-cart/components/details/saved-cart-details-action/saved-cart-details-action.component.ts + class: SAVED_CART_DETAILS_ACTION_COMPONENT, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + deprecatedParams: [ + { + className: SAVED_CART_DETAILS_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: SAVED_CART_FACADE, + importPath: SPARTACUS_CART_SAVED_CART_ROOT, + }, + { + className: ROUTING_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: GLOBAL_MESSAGE_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + { + className: CLEAR_CHECKOUT_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + removeParams: [ + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + ], +}; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/saved-cart-details-overview.component.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/saved-cart-details-overview.component.migration.ts new file mode 100644 index 00000000000..bf77ddb227f --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/saved-cart-details-overview.component.migration.ts @@ -0,0 +1,83 @@ +import { + ANGULAR_CORE, + LAUNCH_DIALOG_SERVICE, + SAVED_CART_DETAILS_OVERVIEW_COMPONENT, + SAVED_CART_DETAILS_SERVICE, + SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + SPARTACUS_CART_SAVED_CART_COMPONENTS, + SPARTACUS_CORE, + SPARTACUS_STOREFRONTLIB, + TRANSLATION_SERVICE, + VIEW_CONTAINER_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const SAVED_CART_DETAILS_OVERVIEW_COMPONENT_MIGRATION_V1: ConstructorDeprecation = { + // feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.ts + class: SAVED_CART_DETAILS_OVERVIEW_COMPONENT, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + deprecatedParams: [ + { + className: SAVED_CART_DETAILS_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: TRANSLATION_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + ], + removeParams: [ + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + ], + addParams: [ + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], +}; + +export const SAVED_CART_DETAILS_OVERVIEW_COMPONENT_MIGRATION_V2: ConstructorDeprecation = { + // feature-libs/cart/saved-cart/components/details/saved-cart-details-overview/saved-cart-details-overview.component.ts + class: SAVED_CART_DETAILS_OVERVIEW_COMPONENT, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + deprecatedParams: [ + { + className: SAVED_CART_DETAILS_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: TRANSLATION_SERVICE, + importPath: SPARTACUS_CORE, + }, + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + { + className: VIEW_CONTAINER_REF, + importPath: ANGULAR_CORE, + }, + { + className: LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + }, + ], + removeParams: [ + { + className: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + }, + ], +}; diff --git a/projects/schematics/src/migrations/4_0/constructor-deprecations/data/window-ref.migration.ts b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/window-ref.migration.ts new file mode 100644 index 00000000000..151e8052e12 --- /dev/null +++ b/projects/schematics/src/migrations/4_0/constructor-deprecations/data/window-ref.migration.ts @@ -0,0 +1,58 @@ +import { + ANGULAR_COMMON, + ANGULAR_CORE, + ANY_TYPE, + DOCUMENT, + DOCUMENT_STRING, + OBJECT_TYPE, + PLATFORM, + PLATFORM_ID_STRING, + SERVER_REQUEST_URL_STRING, + SERVER_REQUEST_ORIGIN_STRING, + SPARTACUS_CORE, + STRING_TYPE, + WINDOW_REF, +} from '../../../../shared/constants'; +import { ConstructorDeprecation } from '../../../../shared/utils/file-utils'; + +export const WINDOW_REF_MIGRATION: ConstructorDeprecation = { + // projects/core/src/window/window-ref.ts + class: WINDOW_REF, + importPath: SPARTACUS_CORE, + deprecatedParams: [ + { + className: DOCUMENT, + literalInference: ANY_TYPE, + injectionToken: { + token: DOCUMENT_STRING, + importPath: ANGULAR_COMMON, + }, + }, + ], + addParams: [ + { + className: PLATFORM, + literalInference: OBJECT_TYPE, + injectionToken: { + token: PLATFORM_ID_STRING, + importPath: ANGULAR_CORE, + }, + }, + { + className: SERVER_REQUEST_URL_STRING, + literalInference: STRING_TYPE, + injectionToken: { + token: SERVER_REQUEST_URL_STRING, + importPath: SPARTACUS_CORE, + }, + }, + { + className: SERVER_REQUEST_ORIGIN_STRING, + literalInference: STRING_TYPE, + injectionToken: { + token: SERVER_REQUEST_ORIGIN_STRING, + importPath: SPARTACUS_CORE, + }, + }, + ], +}; diff --git a/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/data/currency.service.migration.ts b/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/data/currency.service.migration.ts new file mode 100644 index 00000000000..ad20d4e8883 --- /dev/null +++ b/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/data/currency.service.migration.ts @@ -0,0 +1,17 @@ +import { + CURRENCY_SERVICE, + INITIALIZE, + SPARTACUS_CORE, + TODO_SPARTACUS, +} from '../../../../shared/constants'; +import { MethodPropertyDeprecation } from '../../../../shared/utils/file-utils'; + +// projects/core/src/site-context/facade/currency.service.ts +export const CURRENCY_SERVICE_MIGRATION: MethodPropertyDeprecation[] = [ + { + class: CURRENCY_SERVICE, + importPath: SPARTACUS_CORE, + deprecatedNode: INITIALIZE, + comment: `// ${TODO_SPARTACUS} Method '${INITIALIZE}' was removed. The state initialization is done with the 'CurrencyInitializer' .`, + }, +]; diff --git a/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/data/language.service.migration.ts b/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/data/language.service.migration.ts new file mode 100644 index 00000000000..cff6da5c885 --- /dev/null +++ b/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/data/language.service.migration.ts @@ -0,0 +1,17 @@ +import { + INITIALIZE, + LANGUAGE_SERVICE, + SPARTACUS_CORE, + TODO_SPARTACUS, +} from '../../../../shared/constants'; +import { MethodPropertyDeprecation } from '../../../../shared/utils/file-utils'; + +// projects/core/src/site-context/facade/language.service.ts +export const LANGUAGE_SERVICE_MIGRATION: MethodPropertyDeprecation[] = [ + { + class: LANGUAGE_SERVICE, + importPath: SPARTACUS_CORE, + deprecatedNode: INITIALIZE, + comment: `// ${TODO_SPARTACUS} Method '${INITIALIZE}' was removed. The state initialization is done with the 'LanguageInitializer' .`, + }, +]; diff --git a/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/methods-and-properties-deprecations.ts b/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/methods-and-properties-deprecations.ts index 5eb6426395a..0ee206ad461 100644 --- a/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/methods-and-properties-deprecations.ts +++ b/projects/schematics/src/migrations/4_0/methods-and-properties-deprecations/methods-and-properties-deprecations.ts @@ -1,8 +1,13 @@ import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; import { MethodPropertyDeprecation } from '../../../shared/utils/file-utils'; import { migrateMethodPropertiesDeprecation } from '../../mechanism/methods-and-properties-deprecations/methods-and-properties-deprecations'; +import { CURRENCY_SERVICE_MIGRATION } from './data/currency.service.migration'; +import { LANGUAGE_SERVICE_MIGRATION } from './data/language.service.migration'; -export const METHOD_PROPERTY_DATA: MethodPropertyDeprecation[] = []; +export const METHOD_PROPERTY_DATA: MethodPropertyDeprecation[] = [ + ...LANGUAGE_SERVICE_MIGRATION, + ...CURRENCY_SERVICE_MIGRATION, +]; export function migrate(): Rule { return (tree: Tree, context: SchematicContext) => { diff --git a/projects/schematics/src/migrations/4_0/removed-public-api-deprecations/removed-public-api-deprecation.ts b/projects/schematics/src/migrations/4_0/removed-public-api-deprecations/removed-public-api-deprecation.ts index 5740724ab10..e1f91d6c527 100644 --- a/projects/schematics/src/migrations/4_0/removed-public-api-deprecations/removed-public-api-deprecation.ts +++ b/projects/schematics/src/migrations/4_0/removed-public-api-deprecations/removed-public-api-deprecation.ts @@ -1,20 +1,64 @@ import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; import { + ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + ASM_ADAPTER, + ASM_AUTH_HTTP_HEADER_SERVICE, + ASM_AUTH_SERVICE, + ASM_AUTH_STORAGE_SERVICE, + ASM_CONFIG, + ASM_CONNECTOR, + ASM_FEATURE, + ASM_MODULE, + ASM_SERVICE, + ASM_STATE, + ASM_STATE_PERSISTENCE_SERVICE, + ASM_UI, + ASM_UI_ACTION, + ASM_UI_UPDATE, + ASM_UI_UPDATE_CLASS, + CS_AGENT_AUTH_SERVICE, + CUSTOMER_ACTION, + CUSTOMER_SEARCH, + CUSTOMER_SEARCH_CLASS, + CUSTOMER_SEARCH_DATA, + CUSTOMER_SEARCH_FAIL, + CUSTOMER_SEARCH_FAIL_CLASS, + CUSTOMER_SEARCH_OPTIONS, + CUSTOMER_SEARCH_PAGE, + CUSTOMER_SEARCH_PAGE_NORMALIZER, + CUSTOMER_SEARCH_RESET, + CUSTOMER_SEARCH_RESET_CLASS, + CUSTOMER_SEARCH_SUCCESS, + CUSTOMER_SEARCH_SUCCESS_CLASS, DEFAULT_LOCAL_STORAGE_KEY, DEFAULT_SESSION_STORAGE_KEY, DEFAULT_STATE_CONFIG, - SPARTACUS_CORE, -} from '../../../shared/constants'; -import { DeprecatedNode } from '../../../shared/utils/file-utils'; -import { removedPublicApiDeprecation } from '../../mechanism/removed-public-api-deprecations/removed-public-api-deprecation'; -import { + GET_ASM_STATE, + GET_ASM_UI, + GET_CUSTOMER_SEARCH_RESULTS, + GET_CUSTOMER_SEARCH_RESULTS_LOADER_STATE, + GET_CUSTOMER_SEARCH_RESULTS_LOADING, + LOGOUT_CUSTOMER_SUPPORT_AGENT, + LOGOUT_CUSTOMER_SUPPORT_AGENT_CLASS, + PERSONALIZATION_ACTION, + PERSONALIZATION_CONFIG, + PERSONALIZATION_CONTEXT, + PERSONALIZATION_CONTEXT_SERVICE, + PERSONALIZATION_MODULE, + PRODUCT_VARIANTS_MODULE, PRODUCT_VARIANT_COMPONENT, PRODUCT_VARIANT_GUARD, PRODUCT_VARIANT_STYLE_ICONS_COMPONENT, PRODUCT_VARIANT_STYLE_ICONS_MODULE, - PRODUCT_VARIANTS_MODULE, + REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + SPARTACUS_CART_SAVED_CART_COMPONENTS, + SPARTACUS_CORE, SPARTACUS_PRODUCT_VARIANTS_COMPONENTS, SPARTACUS_STOREFRONTLIB, + STATE_WITH_ASM, + SYNCED_ASM_STATE, + TOKEN_TARGET, VARIANT_COLOR_SELECTOR_COMPONENT, VARIANT_COLOR_SELECTOR_MODULE, VARIANT_SIZE_SELECTOR_COMPONENT, @@ -24,8 +68,302 @@ import { VARIANT_STYLE_SELECTOR_COMPONENT, VARIANT_STYLE_SELECTOR_MODULE, } from '../../../shared/constants'; +import { DeprecatedNode } from '../../../shared/utils/file-utils'; +import { removedPublicApiDeprecation } from '../../mechanism/removed-public-api-deprecations/removed-public-api-deprecation'; export const REMOVED_PUBLIC_API_DATA: DeprecatedNode[] = [ + // projects/storefrontlib/src/cms-components/asm/asm.module.ts + { + node: ASM_MODULE, + importPath: SPARTACUS_STOREFRONTLIB, + comment: `'${ASM_MODULE}' was moved to @spartacus/asm/components.`, + }, + // projects/core/src/asm/asm.module.ts + { + node: ASM_MODULE, + importPath: SPARTACUS_CORE, + comment: `'${ASM_MODULE}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/config/asm-config.ts + { + node: ASM_CONFIG, + importPath: SPARTACUS_CORE, + comment: `'${ASM_CONFIG}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/connectors/asm.adapter.ts + { + node: ASM_ADAPTER, + importPath: SPARTACUS_CORE, + comment: `'${ASM_ADAPTER}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/connectors/asm.connector.ts + { + node: ASM_CONNECTOR, + importPath: SPARTACUS_CORE, + comment: `'${ASM_CONNECTOR}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/connectors/converters.ts + { + node: CUSTOMER_SEARCH_PAGE_NORMALIZER, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_PAGE_NORMALIZER}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/facade/asm.service.ts + { + node: ASM_SERVICE, + importPath: SPARTACUS_CORE, + comment: `'${ASM_SERVICE}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/facade/csagent-auth.service.ts + { + node: CS_AGENT_AUTH_SERVICE, + importPath: SPARTACUS_CORE, + comment: `'${CS_AGENT_AUTH_SERVICE}' was moved to @spartacus/asm/root.`, + }, + // projects/core/src/asm/models/asm.models.ts + { + node: CUSTOMER_SEARCH_PAGE, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_PAGE}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/models/asm.models.ts + { + node: CUSTOMER_SEARCH_OPTIONS, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_OPTIONS}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/models/asm.models.ts + { + node: ASM_UI, + importPath: SPARTACUS_CORE, + comment: `'${ASM_UI}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/services/asm-auth-http-header.service.ts + { + node: ASM_AUTH_HTTP_HEADER_SERVICE, + importPath: SPARTACUS_CORE, + comment: `'${ASM_AUTH_HTTP_HEADER_SERVICE}' was moved to @spartacus/asm/root.`, + }, + // projects/core/src/asm/services/asm-auth.service.ts + { + node: TOKEN_TARGET, + importPath: SPARTACUS_CORE, + comment: `'${TOKEN_TARGET}' was moved to @spartacus/asm/root.`, + }, + // projects/core/src/asm/services/asm-auth.service.ts + { + node: ASM_AUTH_SERVICE, + importPath: SPARTACUS_CORE, + comment: `'${ASM_AUTH_SERVICE}' was moved to @spartacus/asm/root.`, + }, + // feature-libs/asm/root/services/asm-auth-storage.service.ts + { + node: ASM_AUTH_STORAGE_SERVICE, + importPath: SPARTACUS_CORE, + comment: `'${ASM_AUTH_STORAGE_SERVICE}' was moved to @spartacus/asm/root.`, + }, + // projects/core/src/asm/services/asm-state-persistence.service.ts + { + node: SYNCED_ASM_STATE, + importPath: SPARTACUS_CORE, + comment: `'${SYNCED_ASM_STATE}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/services/asm-state-persistence.service.ts + { + node: ASM_STATE_PERSISTENCE_SERVICE, + importPath: SPARTACUS_CORE, + comment: `'${ASM_STATE_PERSISTENCE_SERVICE}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/asm-ui.action.ts + { + node: ASM_UI_UPDATE, + importPath: SPARTACUS_CORE, + comment: `'${ASM_UI_UPDATE}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/asm-ui.action.ts + { + node: ASM_UI_UPDATE_CLASS, + importPath: SPARTACUS_CORE, + comment: `'${ASM_UI_UPDATE_CLASS}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/asm-ui.action.ts + { + node: ASM_UI_ACTION, + importPath: SPARTACUS_CORE, + comment: `'${ASM_UI_ACTION}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/customer.action.ts + { + node: CUSTOMER_SEARCH, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/customer.action.ts + { + node: CUSTOMER_SEARCH_CLASS, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_CLASS}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/customer.action.ts + { + node: CUSTOMER_SEARCH_FAIL, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_FAIL}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/customer.action.ts + { + node: CUSTOMER_SEARCH_FAIL_CLASS, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_FAIL_CLASS}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/customer.action.ts + { + node: CUSTOMER_SEARCH_SUCCESS, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_SUCCESS}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/customer.action.ts + { + node: CUSTOMER_SEARCH_SUCCESS_CLASS, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_SUCCESS_CLASS}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/customer.action.ts + { + node: CUSTOMER_SEARCH_RESET, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_RESET}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/customer.action.ts + { + node: CUSTOMER_SEARCH_RESET_CLASS, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_RESET_CLASS}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/customer.action.ts + { + node: CUSTOMER_ACTION, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_ACTION}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/logout-agent.action.ts + { + node: LOGOUT_CUSTOMER_SUPPORT_AGENT, + importPath: SPARTACUS_CORE, + comment: `'${LOGOUT_CUSTOMER_SUPPORT_AGENT}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/actions/logout-agent.action.ts + { + node: LOGOUT_CUSTOMER_SUPPORT_AGENT_CLASS, + importPath: SPARTACUS_CORE, + comment: `'${LOGOUT_CUSTOMER_SUPPORT_AGENT_CLASS}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/asm-state.ts + { + node: ASM_FEATURE, + importPath: SPARTACUS_CORE, + comment: `'${ASM_FEATURE}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/asm-state.ts + { + node: CUSTOMER_SEARCH_DATA, + importPath: SPARTACUS_CORE, + comment: `'${CUSTOMER_SEARCH_DATA}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/asm-state.ts + { + node: STATE_WITH_ASM, + importPath: SPARTACUS_CORE, + comment: `'${STATE_WITH_ASM}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/asm-state.ts + { + node: ASM_STATE, + importPath: SPARTACUS_CORE, + comment: `'${ASM_STATE}' was moved to @spartacus/asm/core.`, + }, + + // projects/core/src/asm/store/selectors/asm-ui.selectors.ts + { + node: GET_ASM_UI, + importPath: SPARTACUS_CORE, + comment: `'${GET_ASM_UI}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/selectors/asm-ui.selectors.ts + { + node: GET_CUSTOMER_SEARCH_RESULTS_LOADER_STATE, + importPath: SPARTACUS_CORE, + comment: `'${GET_CUSTOMER_SEARCH_RESULTS_LOADER_STATE}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/selectors/asm-ui.selectors.ts + { + node: GET_CUSTOMER_SEARCH_RESULTS, + importPath: SPARTACUS_CORE, + comment: `'${GET_CUSTOMER_SEARCH_RESULTS}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/selectors/asm-ui.selectors.ts + { + node: GET_CUSTOMER_SEARCH_RESULTS_LOADING, + importPath: SPARTACUS_CORE, + comment: `'${GET_CUSTOMER_SEARCH_RESULTS_LOADING}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/selectors/asm-ui.selectors.ts + { + node: GET_CUSTOMER_SEARCH_RESULTS_LOADING, + importPath: SPARTACUS_CORE, + comment: `'${GET_CUSTOMER_SEARCH_RESULTS_LOADING}' was moved to @spartacus/asm/core.`, + }, + // projects/core/src/asm/store/selectors/feature.selector.ts + { + node: GET_ASM_STATE, + importPath: SPARTACUS_CORE, + comment: `'${GET_ASM_STATE}' was moved to @spartacus/asm/core.`, + }, + { + node: SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_CART_SAVED_CART_COMPONENTS, + comment: `'${SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE}' has been removed.' 'openDialog' method has been moved to 'LaunchDialogService'.`, + }, + { + node: ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + comment: `'${ANONYMOUS_CONSENT_LAUNCH_DIALOG_SERVICE}' has been removed.' 'openDialog' method has been moved to 'LaunchDialogService'.`, + }, + { + node: REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE, + importPath: SPARTACUS_STOREFRONTLIB, + comment: `'${REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE}' has been removed.' 'openDialog' method has been moved to 'LaunchDialogService'.`, + }, + // projects/core/src/personalization/personalization.module.ts + { + node: PERSONALIZATION_MODULE, + importPath: SPARTACUS_CORE, + comment: `${PERSONALIZATION_MODULE} was removed. Use @spartacus/tracking/personalization instead.`, + }, + // projects/core/src/personalization/config/personalization-config.ts + { + node: PERSONALIZATION_CONFIG, + importPath: SPARTACUS_CORE, + comment: `${PERSONALIZATION_CONFIG} was moved to @spartacus/tracking/personalization/root.`, + }, + // projects/core/src/personalization/services/personalization-context.service.ts + { + node: PERSONALIZATION_CONTEXT_SERVICE, + importPath: SPARTACUS_CORE, + comment: `${PERSONALIZATION_CONTEXT_SERVICE} was moved to @spartacus/tracking/personalization/core.`, + }, + // projects/core/src/personalization/model/personalization-context.model.ts + { + node: PERSONALIZATION_ACTION, + importPath: SPARTACUS_CORE, + comment: `${PERSONALIZATION_ACTION} was moved to @spartacus/tracking/personalization/core.`, + }, + // projects/core/src/personalization/model/personalization-context.model.ts + { + node: PERSONALIZATION_CONTEXT, + importPath: SPARTACUS_CORE, + comment: `${PERSONALIZATION_CONTEXT} was moved to @spartacus/tracking/personalization/core.`, + }, // projects/storefrontlib/src/cms-components/product/product-variants/product-variants.module.ts { node: PRODUCT_VARIANTS_MODULE, diff --git a/projects/schematics/src/ng-add/index_spec.ts b/projects/schematics/src/ng-add/index_spec.ts index 226e575df5b..4ab338e40a4 100644 --- a/projects/schematics/src/ng-add/index_spec.ts +++ b/projects/schematics/src/ng-add/index_spec.ts @@ -36,7 +36,6 @@ describe('Spartacus Schematics: ng-add', () => { const defaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/projects/schematics/src/shared/constants.ts b/projects/schematics/src/shared/constants.ts index 23bcd59931d..2721c217b71 100644 --- a/projects/schematics/src/shared/constants.ts +++ b/projects/schematics/src/shared/constants.ts @@ -27,6 +27,8 @@ export const SPARTACUS_ORGANIZATION_ADMINISTRATION_CORE = `${SPARTACUS_ORGANIZAT export const SPARTACUS_ORGANIZATION_ADMINISTRATION_COMPONENTS = `${SPARTACUS_ORGANIZATION}/administration/components`; export const SPARTACUS_ASM = '@spartacus/asm'; export const SPARTACUS_CART = '@spartacus/cart'; +export const SPARTACUS_CART_SAVED_CART_COMPONENTS = `${SPARTACUS_CART}/saved-cart/components`; +export const SPARTACUS_CART_SAVED_CART_ROOT = `${SPARTACUS_CART}/saved-cart/root`; export const SPARTACUS_PRODUCT = '@spartacus/product'; export const SPARTACUS_PRODUCT_CONFIGURATOR = '@spartacus/product-configurator'; export const SPARTACUS_PRODUCT_CONFIGURATOR_COMMON = `${SPARTACUS_PRODUCT_CONFIGURATOR}/common`; @@ -229,7 +231,7 @@ export const DYNAMIC_ATTRIBUTE_SERVICE = 'DynamicAttributeService'; export const OUTLET_DIRECTIVE = 'OutletDirective'; export const OUTLET_SERVICE = 'OutletService'; export const DEFER_LOADER_SERVICE = 'DeferLoaderService'; -export const LAUNCH_DIALOG_SERVICE = 'LaunchComponentService'; +export const LAUNCH_DIALOG_SERVICE = 'LaunchDialogService'; export const PLACE_ORDER_COMPONENT = 'PlaceOrderComponent'; export const USER_INTERESTS_SERVICE = 'UserInterestsService'; export const USER_NOTIFICATION_PREFERENCE_SERVICE = @@ -324,8 +326,6 @@ export const LANGUAGE_SERVICE = 'LanguageService'; export const CURRENCY_SERVICE = 'CurrencyService'; export const SEARCH_BOX_SERVICE = 'SearchboxService'; -export const ASM_AUTH_SERVICE = 'AsmAuthService'; - export const FORGOT_PASSWORD_COMPONENT = 'ForgotPasswordComponent'; export const AUTH_CONFIG_SERVICE = 'AuthConfigService'; export const CLOSE_ACCOUNT_MODAL_COMPONENT = 'CloseAccountModalComponent'; @@ -344,6 +344,23 @@ export const UNIT_CHILDREN_COMPONENT = 'UnitChildrenComponent'; export const UNIT_COST_CENTER_LIST_COMPONENT = 'UnitCostCenterListComponent'; export const UNIT_USER_LIST_COMPONENT = 'UnitUserListComponent'; +export const SAVED_CART_FORM_LAUNCH_DIALOG_SERVICE = + 'SavedCartFormLaunchDialogService'; +export const ADD_TO_SAVED_CART_COMPONENT = 'AddToSavedCartComponent '; +export const SAVED_CART_DETAILS_ACTION_COMPONENT = + 'SavedCartDetailsActionComponent '; +export const SAVED_CART_DETAILS_OVERVIEW_COMPONENT = + 'SavedCartDetailsOverviewComponent '; +export const SAVED_CART_DETAILS_SERVICE = 'SavedCartDetailsService'; +export const SAVED_CART_FACADE = 'SavedCartFacade'; +export const CLEAR_CHECKOUT_SERVICE = 'ClearCheckoutService'; + +export const REPLENISHMENT_ORDER_CANCELLATION_LAUNCH_DIALOG_SERVICE = + 'ReplenishmentOrderCancellationLaunchDialogService'; +export const REPLENISHMENT_ORDER_CANCELLATION_COMPONENT = + 'ReplenishmentOrderCancellationComponent'; +export const REPLENISHMENT_ORDER_HISTORY_COMPONENT = + 'ReplenishmentOrderHistoryComponent'; export const COMMON_CONFIGURATOR_UTILS_SERVICE = 'CommonConfiguratorUtilsService'; export const CONFIGURATOR_ATTRIBUTE_QUANTITY_SERVICE = @@ -369,6 +386,7 @@ export const CONTEXT = 'context'; export const SEMANTIC_ROUTE = 'semanticRoute'; export const URL = 'url'; export const PARAMS = 'params'; +export const INITIALIZE = 'initialize'; /***** Classes end *****/ @@ -470,12 +488,51 @@ export const KYMA_MODULE = 'KymaModule'; export const KYMA_SERVICE = 'KymaService'; export const KYMA_CONFIG = 'KymaConfig'; -export const CS_AGENT_AUTH_SERVICE = 'CsAgentAuthService'; export const ASM_SELECTORS = 'AsmSelectors'; export const ASM_ACTIONS = 'AsmActions'; export const CSAGENT_TOKEN_DATA = 'CSAGENT_TOKEN_DATA'; export const CUSTOMER_SUPPORT_AGENT_TOKEN_INTERCEPTOR = 'CustomerSupportAgentTokenInterceptor '; +export const ASM_MODULE = 'AsmModule'; +export const ASM_CONFIG = 'AsmConfig'; +export const ASM_ADAPTER = 'AsmAdapter'; +export const ASM_CONNECTOR = 'AsmConnector'; +export const CUSTOMER_SEARCH_PAGE_NORMALIZER = + 'CUSTOMER_SEARCH_PAGE_NORMALIZER'; +export const ASM_SERVICE = 'AsmService'; +export const CS_AGENT_AUTH_SERVICE = 'CsAgentAuthService'; +export const CUSTOMER_SEARCH_PAGE = 'CustomerSearchPage'; +export const CUSTOMER_SEARCH_OPTIONS = 'CustomerSearchOptions'; +export const ASM_UI = 'AsmUi'; +export const ASM_AUTH_HTTP_HEADER_SERVICE = 'AsmAuthHttpHeaderService'; +export const TOKEN_TARGET = 'TokenTarget'; +export const ASM_AUTH_STORAGE_SERVICE = 'AsmAuthStorageService'; +export const ASM_AUTH_SERVICE = 'AsmAuthService'; +export const SYNCED_ASM_STATE = 'SyncedAsmState'; +export const ASM_STATE_PERSISTENCE_SERVICE = 'AsmStatePersistenceService'; +export const ASM_UI_UPDATE = 'ASM_UI_UPDATE'; +export const ASM_UI_UPDATE_CLASS = 'ASM_UI_UPDATE_CLASS'; +export const ASM_UI_ACTION = 'AsmUiAction'; +export const CUSTOMER_SEARCH = 'CUSTOMER_SEARCH'; +export const CUSTOMER_SEARCH_CLASS = 'CUSTOMER_SEARCH_CLASS'; +export const CUSTOMER_SEARCH_FAIL = 'CUSTOMER_SEARCH_FAIL'; +export const CUSTOMER_SEARCH_FAIL_CLASS = 'CUSTOMER_SEARCH_FAIL_CLASS'; +export const CUSTOMER_SEARCH_SUCCESS = 'CUSTOMER_SEARCH_SUCCESS'; +export const CUSTOMER_SEARCH_SUCCESS_CLASS = 'CUSTOMER_SEARCH_SUCCESS_CLASS'; +export const CUSTOMER_SEARCH_RESET = 'CUSTOMER_SEARCH_RESET'; +export const CUSTOMER_SEARCH_RESET_CLASS = 'CUSTOMER_SEARCH_RESET_CLASS'; +export const CUSTOMER_ACTION = 'CustomerAction'; +export const ASM_FEATURE = 'ASM_FEATURE'; +export const CUSTOMER_SEARCH_DATA = 'CUSTOMER_SEARCH_DATA'; +export const STATE_WITH_ASM = 'StateWithAsm'; +export const ASM_STATE = 'AsmState'; +export const GET_ASM_UI = 'getAsmUi'; +export const GET_CUSTOMER_SEARCH_RESULTS_LOADER_STATE = + 'getCustomerSearchResultsLoaderState'; +export const GET_CUSTOMER_SEARCH_RESULTS = 'getCustomerSearchResults'; +export const GET_CUSTOMER_SEARCH_RESULTS_LOADING = + 'getCustomerSearchResultsLoading'; +export const GET_ASM_STATE = 'getAsmState'; export const OCC_STORE_FINDER_ADAPTER = 'OccStoreFinderAdapter'; export const STORE_FINDER_OCC_MODULE = 'StoreFinderOccModule'; @@ -557,6 +614,12 @@ export const DEFAULT_STATE_CONFIG = 'defaultStateConfig'; export const DEFAULT_LOCAL_STORAGE_KEY = 'DEFAULT_LOCAL_STORAGE_KEY'; export const DEFAULT_SESSION_STORAGE_KEY = 'DEFAULT_SESSION_STORAGE_KEY'; +export const PERSONALIZATION_MODULE = 'PersonalizationModule'; +export const PERSONALIZATION_CONFIG = 'PersonalizationConfig'; +export const PERSONALIZATION_CONTEXT_SERVICE = 'PersonalizationContextService'; +export const PERSONALIZATION_ACTION = 'PersonalizationAction'; +export const PERSONALIZATION_CONTEXT = 'PersonalizationContext'; + /***** Removed public api end *****/ /***** Properties start *****/ @@ -571,6 +634,8 @@ export const LOAD_CLIENT_TOKEN_SUCCESS = 'LOAD_CLIENT_TOKEN_SUCCESS'; export const LOAD_CLIENT_TOKEN_FAIL_CLASS = 'LoadClientTokenFail'; export const LOAD_CLIENT_TOKEN_FAIL = 'LOAD_CLIENT_TOKEN_FAIL'; export const LOGOUT_CUSTOMER_SUPPORT_AGENT = 'LOGOUT_CUSTOMER_SUPPORT_AGENT'; +export const LOGOUT_CUSTOMER_SUPPORT_AGENT_CLASS = + 'LOGOUT_CUSTOMER_SUPPORT_AGENT_CLASS'; export const LOAD_USER_TOKEN = 'LOAD_USER_TOKEN'; export const LOAD_USER_TOKEN_FAIL = 'LOAD_USER_TOKEN_FAIL'; export const LOAD_USER_TOKEN_SUCCESS = 'LOAD_USER_TOKEN_SUCCESS'; @@ -620,6 +685,12 @@ export const INJECT_DECORATOR = 'Inject'; export const PLATFORM = 'Platform'; export const PLATFORM_ID_STRING = 'PLATFORM_ID'; export const ANY_TYPE = 'any'; +export const OBJECT_TYPE = 'Object'; +export const STRING_TYPE = 'string'; +export const DOCUMENT = 'Document'; +export const DOCUMENT_STRING = 'DOCUMENT'; +export const SERVER_REQUEST_URL_STRING = 'SERVER_REQUEST_URL'; +export const SERVER_REQUEST_ORIGIN_STRING = 'SERVER_REQUEST_ORIGIN'; /***** Properties end *****/ /***** APIs start *****/ diff --git a/projects/schematics/src/shared/utils/lib-utils.ts b/projects/schematics/src/shared/utils/lib-utils.ts index 4b27e739ece..16cdf99b5bf 100644 --- a/projects/schematics/src/shared/utils/lib-utils.ts +++ b/projects/schematics/src/shared/utils/lib-utils.ts @@ -1,6 +1,7 @@ import { dasherize } from '@angular-devkit/core/src/utils/strings'; import { chain, + ExecutionOptions, externalSchematic, noop, Rule, @@ -84,7 +85,7 @@ import { getWorkspace, } from './workspace-utils'; -export interface LibraryOptions { +export interface LibraryOptions extends Partial { project: string; lazy: boolean; features?: string[]; @@ -734,7 +735,8 @@ export function addPackageJsonDependenciesForLibrary< }, {} as Record); const featureOptions = createSpartacusFeatureOptionsForLibrary( options, - cliFeatures + cliFeatures, + false ); addSchematicsTasks(featureOptions, context); @@ -858,7 +860,8 @@ export function createSpartacusFeatureOptionsForLibrary< OPTIONS extends LibraryOptions >( options: OPTIONS, - cliFeatures: Record + cliFeatures: Record, + interactive = true ): { feature: string; options: LibraryOptions; @@ -869,6 +872,7 @@ export function createSpartacusFeatureOptionsForLibrary< ...options, // an empty array means that no library features will be installed. features: cliFeatures[spartacusLibrary] ?? [], + interactive, }, })); } @@ -905,11 +909,17 @@ export function runExternalSpartacusLibrary( `Can't run the Spartacus library schematic, please specify the 'collection' argument.` ); } + + const executionOptions: Partial = { + interactive: taskOptions.options.interactive, + }; + return chain([ externalSchematic( taskOptions.collection, taskOptions.name, - taskOptions.options + taskOptions.options, + executionOptions ), ])(tree, context); }; diff --git a/projects/schematics/src/shared/utils/lib-utils_spec.ts b/projects/schematics/src/shared/utils/lib-utils_spec.ts index 4e20e66bd98..6084e15cd3d 100644 --- a/projects/schematics/src/shared/utils/lib-utils_spec.ts +++ b/projects/schematics/src/shared/utils/lib-utils_spec.ts @@ -103,7 +103,6 @@ describe('Lib utils', () => { const spartacusDefaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/projects/schematics/src/shared/utils/package-utils.ts b/projects/schematics/src/shared/utils/package-utils.ts index 938f2fa5edc..e1212a160a0 100644 --- a/projects/schematics/src/shared/utils/package-utils.ts +++ b/projects/schematics/src/shared/utils/package-utils.ts @@ -163,7 +163,7 @@ export function checkIfSSRIsUsed(tree: Tree): boolean { return !!(isServerConfiguration && isServerSideAvailable); } -export function prepareSpartacusDependencies(b2b: boolean): NodeDependency[] { +export function prepareSpartacusDependencies(): NodeDependency[] { const spartacusVersion = getPrefixedSpartacusSchematicsVersion(); const spartacusDependencies: NodeDependency[] = [ @@ -188,13 +188,6 @@ export function prepareSpartacusDependencies(b2b: boolean): NodeDependency[] { name: SPARTACUS_STYLES, }, ]; - if (b2b) { - spartacusDependencies.push({ - type: NodeDependencyType.Default, - version: spartacusVersion, - name: SPARTACUS_SETUP, - }); - } return spartacusDependencies; } diff --git a/projects/schematics/src/shared/utils/workspace-utils_spec.ts b/projects/schematics/src/shared/utils/workspace-utils_spec.ts index be9dbd6a9f3..12a04741f54 100644 --- a/projects/schematics/src/shared/utils/workspace-utils_spec.ts +++ b/projects/schematics/src/shared/utils/workspace-utils_spec.ts @@ -14,6 +14,7 @@ import { import { Schema as WorkspaceOptions } from '@schematics/angular/workspace/schema'; import * as path from 'path'; import { Schema as SpartacusOptions } from '../../add-spartacus/schema'; +import { SPARTACUS_CORE } from '../../shared/constants'; import { buildDefaultPath, getAngularJsonFile, @@ -27,7 +28,6 @@ import { isWorkspaceSchema, validateSpartacusInstallation, } from './workspace-utils'; -import { SPARTACUS_CORE } from '../../shared/constants'; const collectionPath = path.join(__dirname, '../../collection.json'); const schematicRunner = new SchematicTestRunner('schematics', collectionPath); @@ -158,7 +158,6 @@ describe('Workspace utils', () => { }; const defaultOptions: SpartacusOptions = { project: 'schematics-test', - configuration: 'b2c', lazy: true, features: [], }; diff --git a/projects/storefrontlib/src/cms-components/anonymous-consent-management/anonymous-consent-launch-dialog.service.spec.ts b/projects/storefrontlib/src/cms-components/anonymous-consent-management/anonymous-consent-launch-dialog.service.spec.ts deleted file mode 100644 index f7be20ce4ef..00000000000 --- a/projects/storefrontlib/src/cms-components/anonymous-consent-management/anonymous-consent-launch-dialog.service.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -// TODO(#12167): remove the file -import { Component, ComponentRef, ViewContainerRef } from '@angular/core'; -import { TestBed } from '@angular/core/testing'; -import { of } from 'rxjs'; -import { LaunchDialogService, LAUNCH_CALLER } from '../../layout'; -import { AnonymousConsentLaunchDialogService } from './anonymous-consent-launch-dialog.service'; - -@Component({ - template: '', -}) -class TestContainerComponent { - constructor(public vcr: ViewContainerRef) {} -} - -class MockLaunchDialogService { - launch() {} - clear() {} - get dialogClose() { - return of('close'); - } -} - -describe('AnonymousConsentLaunchDialogService', () => { - let service: AnonymousConsentLaunchDialogService; - let launchDialogService: LaunchDialogService; - let component: TestContainerComponent; - let componentRef: ComponentRef; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - { - provide: LaunchDialogService, - useClass: MockLaunchDialogService, - }, - ], - declarations: [TestContainerComponent], - }).compileComponents(); - - service = TestBed.inject(AnonymousConsentLaunchDialogService); - launchDialogService = TestBed.inject(LaunchDialogService); - component = TestBed.createComponent(TestContainerComponent) - .componentInstance; - componentRef = TestBed.createComponent(TestContainerComponent).componentRef; - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - describe('openDialog', () => { - beforeEach(() => { - spyOn(launchDialogService, 'launch').and.returnValue(of(componentRef)); - }); - - it('should call LaunchDialogService launch', () => { - service.openDialog(null, component.vcr); - - expect(launchDialogService.launch).toHaveBeenCalledWith( - LAUNCH_CALLER.ANONYMOUS_CONSENT, - component.vcr - ); - }); - - it('should call LaunchDialogService clear on close', () => { - spyOn(launchDialogService, 'clear'); - - const comp = service.openDialog(null, component.vcr); - - comp.subscribe(); - - expect(launchDialogService.clear).toHaveBeenCalledWith( - LAUNCH_CALLER.ANONYMOUS_CONSENT - ); - }); - - it('should destroy component on close', () => { - spyOn(componentRef, 'destroy'); - - const comp = service.openDialog(null, component.vcr); - - comp.subscribe(); - - expect(componentRef.destroy).toHaveBeenCalled(); - }); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/anonymous-consent-management/anonymous-consent-launch-dialog.service.ts b/projects/storefrontlib/src/cms-components/anonymous-consent-management/anonymous-consent-launch-dialog.service.ts deleted file mode 100644 index 1cbf3f8b4bc..00000000000 --- a/projects/storefrontlib/src/cms-components/anonymous-consent-management/anonymous-consent-launch-dialog.service.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { ElementRef, Injectable, ViewContainerRef } from '@angular/core'; -import { combineLatest, Observable } from 'rxjs'; -import { filter, map, tap } from 'rxjs/operators'; -import { - LaunchDialogService, - LAUNCH_CALLER, -} from '../../layout/launch-dialog/index'; - -// TODO(#12167): deprecations cleanup -/** - * @deprecated since 3.3 - use `LaunchDialogService` instead - */ -@Injectable({ providedIn: 'root' }) -export class AnonymousConsentLaunchDialogService { - constructor(protected launchDialogService: LaunchDialogService) {} - - /** - * @deprecated since 3.3 - use `LaunchDialogService.openDialog` with LAUNCH_CALLER.ANONYMOUS_CONSENT instead - */ - openDialog( - openElement?: ElementRef, - vcr?: ViewContainerRef - ): Observable | undefined { - const component = this.launchDialogService.launch( - LAUNCH_CALLER.ANONYMOUS_CONSENT, - vcr - ); - - if (component) { - return combineLatest([ - component, - this.launchDialogService.dialogClose, - ]).pipe( - filter(([, close]) => close && close !== undefined), - tap(([comp]) => { - openElement?.nativeElement.focus(); - this.launchDialogService.clear(LAUNCH_CALLER.ANONYMOUS_CONSENT); - comp.destroy(); - }), - map(([comp]) => comp) - ); - } - } -} diff --git a/projects/storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.spec.ts b/projects/storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.spec.ts index 36a3349afca..f37e20372b8 100644 --- a/projects/storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.spec.ts +++ b/projects/storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.spec.ts @@ -7,7 +7,6 @@ import { } from '@spartacus/core'; import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; import { Observable, of } from 'rxjs'; -import { AnonymousConsentLaunchDialogService } from '../anonymous-consent-launch-dialog.service'; import { AnonymousConsentManagementBannerComponent } from './anonymous-consent-management-banner.component'; class MockAnonymousConsentsService { @@ -23,10 +22,6 @@ class MockAnonymousConsentsService { toggleBannerDismissed(_dismissed: boolean): void {} } -class MockAnonymousConsentLaunchDialogService { - openDialog() {} -} - class MockLaunchDialogService implements Partial { openDialog( _caller: LAUNCH_CALLER, @@ -53,11 +48,6 @@ describe('AnonymousConsentManagementBannerComponent', () => { provide: AnonymousConsentsService, useClass: MockAnonymousConsentsService, }, - // TODO(#12167): remove unused class and provider - { - provide: AnonymousConsentLaunchDialogService, - useClass: MockAnonymousConsentLaunchDialogService, - }, { provide: LaunchDialogService, useClass: MockLaunchDialogService, diff --git a/projects/storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.ts b/projects/storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.ts index 1c4509f674d..3eb4b0f7903 100644 --- a/projects/storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.ts +++ b/projects/storefrontlib/src/cms-components/anonymous-consent-management/banner/anonymous-consent-management-banner.component.ts @@ -1,12 +1,9 @@ import { Component, OnDestroy, ViewContainerRef } from '@angular/core'; import { AnonymousConsentsService } from '@spartacus/core'; -import { - LaunchDialogService, - LAUNCH_CALLER, -} from '../../../layout/launch-dialog'; +import { LaunchDialogService } from '../../../layout/launch-dialog/services/launch-dialog.service'; +import { LAUNCH_CALLER } from '../../../layout/launch-dialog/config/launch-config'; import { Observable, Subscription } from 'rxjs'; import { tap } from 'rxjs/operators'; -import { AnonymousConsentLaunchDialogService } from '../anonymous-consent-launch-dialog.service'; @Component({ selector: 'cx-anonymous-consent-management-banner', @@ -17,56 +14,21 @@ export class AnonymousConsentManagementBannerComponent implements OnDestroy { bannerVisible$: Observable = this.anonymousConsentsService.isBannerVisible(); - // TODO(#12167): make launchDialogService a required dependency instead of anonymousConsentLaunchDialogService and remove deprecated constructors - /** - * @deprecated since 3.3 - */ - constructor( - anonymousConsentsService: AnonymousConsentsService, - anonymousConsentLaunchDialogService: AnonymousConsentLaunchDialogService, - vcr: ViewContainerRef - ); - /** - * Default constructor will be - * - * @param {AnonymousConsentsService} anonymousConsentsService - * @param {ViewContainerRef} vcr - * @param {LaunchDialogService} launchDialogService - */ - constructor( - anonymousConsentsService: AnonymousConsentsService, - anonymousConsentLaunchDialogService: AnonymousConsentLaunchDialogService, - vcr: ViewContainerRef, - // eslint-disable-next-line @typescript-eslint/unified-signatures - launchDialogService: LaunchDialogService - ); constructor( protected anonymousConsentsService: AnonymousConsentsService, - protected anonymousConsentLaunchDialogService: AnonymousConsentLaunchDialogService, protected vcr: ViewContainerRef, - protected launchDialogService?: LaunchDialogService + protected launchDialogService: LaunchDialogService ) {} viewDetails(): void { this.hideBanner(); - // TODO(#12167): use launchDialogService only - if (this.launchDialogService) { - const dialog = this.launchDialogService.openDialog( - LAUNCH_CALLER.ANONYMOUS_CONSENT, - null, - this.vcr - ); - if (dialog) { - this.subscriptions.add(dialog.subscribe()); - } - } else { - const dialog = this.anonymousConsentLaunchDialogService.openDialog( - null, - this.vcr - ); - if (dialog) { - this.subscriptions.add(dialog.subscribe()); - } + const dialog = this.launchDialogService.openDialog( + LAUNCH_CALLER.ANONYMOUS_CONSENT, + null, + this.vcr + ); + if (dialog) { + this.subscriptions.add(dialog.subscribe()); } } diff --git a/projects/storefrontlib/src/cms-components/anonymous-consent-management/index.ts b/projects/storefrontlib/src/cms-components/anonymous-consent-management/index.ts index b738f0816a7..46088314066 100644 --- a/projects/storefrontlib/src/cms-components/anonymous-consent-management/index.ts +++ b/projects/storefrontlib/src/cms-components/anonymous-consent-management/index.ts @@ -1,4 +1,3 @@ -export * from './anonymous-consent-launch-dialog.service'; export * from './anonymous-consent-management.module'; export * from './banner/anonymous-consent-management-banner.component'; export * from './open-dialog/anonymous-consent-open-dialog.component'; diff --git a/projects/storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.spec.ts b/projects/storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.spec.ts index 71a5f903309..78d0ae6316c 100644 --- a/projects/storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.spec.ts +++ b/projects/storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.spec.ts @@ -1,7 +1,6 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; import { I18nTestingModule } from '@spartacus/core'; import { ModalOptions, ModalRef, ModalService } from '../../../shared/index'; -import { AnonymousConsentLaunchDialogService } from '../anonymous-consent-launch-dialog.service'; import { AnonymousConsentOpenDialogComponent } from './anonymous-consent-open-dialog.component'; import { ElementRef, ViewContainerRef } from '@angular/core'; import { of } from 'rxjs'; @@ -13,10 +12,6 @@ class MockModalService { } } -class MockAnonymousConsentLaunchDialogService { - openDialog() {} -} - class MockLaunchDialogService implements Partial { openDialog( _caller: LAUNCH_CALLER, @@ -42,11 +37,6 @@ describe('AnonymousConsentOpenDialogComponent', () => { provide: ModalService, useClass: MockModalService, }, - // TODO(#12167): remove unused class and provider - { - provide: AnonymousConsentLaunchDialogService, - useClass: MockAnonymousConsentLaunchDialogService, - }, { provide: LaunchDialogService, useClass: MockLaunchDialogService, diff --git a/projects/storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.ts b/projects/storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.ts index e87fbda4c69..a93714be510 100644 --- a/projects/storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.ts +++ b/projects/storefrontlib/src/cms-components/anonymous-consent-management/open-dialog/anonymous-consent-open-dialog.component.ts @@ -4,12 +4,9 @@ import { ViewChild, ViewContainerRef, } from '@angular/core'; -import { - LaunchDialogService, - LAUNCH_CALLER, -} from '../../../layout/launch-dialog'; +import { LaunchDialogService } from '../../../layout/launch-dialog/services/launch-dialog.service'; +import { LAUNCH_CALLER } from '../../../layout/launch-dialog/config/launch-config'; import { take } from 'rxjs/operators'; -import { AnonymousConsentLaunchDialogService } from '../anonymous-consent-launch-dialog.service'; @Component({ selector: 'cx-anonymous-consent-open-dialog', @@ -18,50 +15,19 @@ import { AnonymousConsentLaunchDialogService } from '../anonymous-consent-launch export class AnonymousConsentOpenDialogComponent { @ViewChild('open') openElement: ElementRef; - // TODO(#12167): make launchDialogService a required dependency instead of anonymousConsentLaunchDialogService and remove deprecated constructors - /** - * @deprecated since 3.3 - */ - constructor( - vcr: ViewContainerRef, - anonymousConsentLaunchDialogService: AnonymousConsentLaunchDialogService - ); - /** - * Default constructor will be - * @param {ViewContainerRef} vcr - * @param {LaunchDialogService} launchDialogService - */ - constructor( - vcr: ViewContainerRef, - anonymousConsentLaunchDialogService: AnonymousConsentLaunchDialogService, - // eslint-disable-next-line @typescript-eslint/unified-signatures - launchDialogService: LaunchDialogService - ); constructor( protected vcr: ViewContainerRef, - protected anonymousConsentLaunchDialogService: AnonymousConsentLaunchDialogService, - protected launchDialogService?: LaunchDialogService + protected launchDialogService: LaunchDialogService ) {} openDialog(): void { - // TODO(#12167): use launchDialogService only - if (this.launchDialogService) { - const dialog = this.launchDialogService.openDialog( - LAUNCH_CALLER.ANONYMOUS_CONSENT, - this.openElement, - this.vcr - ); - if (dialog) { - dialog.pipe(take(1)).subscribe(); - } - } else { - const dialog = this.anonymousConsentLaunchDialogService.openDialog( - this.openElement, - this.vcr - ); - if (dialog) { - dialog.pipe(take(1)).subscribe(); - } + const dialog = this.launchDialogService.openDialog( + LAUNCH_CALLER.ANONYMOUS_CONSENT, + this.openElement, + this.vcr + ); + if (dialog) { + dialog.pipe(take(1)).subscribe(); } } } diff --git a/projects/storefrontlib/src/cms-components/asm/asm-constants.ts b/projects/storefrontlib/src/cms-components/asm/asm-constants.ts deleted file mode 100644 index ea31a65f82e..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const ASM_ENABLED_LOCAL_STORAGE_KEY = 'asm_enabled'; diff --git a/projects/storefrontlib/src/cms-components/asm/asm-loader.module.ts b/projects/storefrontlib/src/cms-components/asm/asm-loader.module.ts deleted file mode 100644 index 95869b6b9c8..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-loader.module.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { APP_INITIALIZER, NgModule } from '@angular/core'; -import { PageComponentModule } from '../../cms-structure/page/component/page-component.module'; -import { AsmEnablerService } from './services/asm-enabler.service'; - -/** - * The ASM loader module takes care of loading the ASM UI - * only in case there's a reason to do so. - */ -@NgModule({ - imports: [CommonModule, PageComponentModule], - providers: [ - { - provide: APP_INITIALIZER, - useFactory: asmFactory, - deps: [AsmEnablerService], - multi: true, - }, - ], -}) -export class AsmLoaderModule {} - -/** - * - * We do not like to block the UI, which is why we delgate loading of ASM - * to a real component; the router and state aren't available in an optimized - * way during the APP_INITIALIZER. - */ -export function asmFactory(asmEnablerService: AsmEnablerService) { - const isReady = () => { - asmEnablerService.load(); - }; - return isReady; -} diff --git a/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.html b/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.html deleted file mode 100644 index bb90308a555..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.html +++ /dev/null @@ -1,63 +0,0 @@ -
-
- - -
- {{ 'asm.mainTitle' | cxTranslate }} -
-
-
- - - - - - - -
-
- - - - - - - - - - - - - - - diff --git a/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.scss b/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.scss deleted file mode 100644 index 3464165af32..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.scss +++ /dev/null @@ -1,148 +0,0 @@ -cx-asm-main-ui { - font-family: Arial, sans-serif; - font-size: 14px; - width: 100%; - display: flex; - flex-direction: column; - - .close, - .logout { - cursor: pointer; - width: 16px; - height: 16px; - border: transparent; - background-color: transparent; - } - - .close { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M14.53 4.53l-1.06-1.06L9 7.94 4.53 3.47 3.47 4.53 7.94 9l-4.47 4.47 1.06 1.06L9 10.06l4.47 4.47 1.06-1.06L10.06 9z'/%3E%3C/svg%3E"); - } - - .logout { - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='%23d1e3ff' d='M11,2.7c1.2,0.6,2.2,1.5,2.9,2.6c1.3,1.9,1.5,4.4,0.6,6.5c-0.3,0.8-0.8,1.6-1.5,2.2c-0.6,0.6-1.4,1.1-2.2,1.5 C9.9,15.8,9,16,8,16c-0.9,0-1.9-0.2-2.7-0.5c-0.8-0.4-1.6-0.9-2.2-1.5c-0.6-0.6-1.1-1.4-1.5-2.2C0.7,9.6,0.9,7.2,2.1,5.3 c0.7-1.1,1.7-2,2.9-2.6v1.1C4.1,4.3,3.3,5.1,2.8,6C2.3,6.9,2,7.9,2,9c0,1.6,0.6,3.2,1.8,4.3c0.5,0.5,1.2,1,1.9,1.3 c1.5,0.6,3.2,0.6,4.7,0c0.7-0.3,1.4-0.7,1.9-1.3C13.4,12.1,14,10.6,14,9c0-1.1-0.3-2.1-0.8-3c-0.5-0.9-1.3-1.7-2.2-2.2 C11,3.8,11,2.7,11,2.7z M8,9C7.7,9,7.5,8.9,7.3,8.7C7.1,8.5,7,8.3,7,8V1c0-0.3,0.1-0.5,0.3-0.7c0.4-0.4,1-0.4,1.4,0 C8.9,0.5,9,0.7,9,1v7c0,0.3-0.1,0.5-0.3,0.7C8.5,8.9,8.2,9,8,9z'/%3E%3C/svg%3E%0A"); - } - - button[type='submit'] { - padding: 0 12px; - white-space: nowrap; - border-radius: 4px; - height: 36px; - font-weight: 400; - - border-style: solid; - border-width: 1px; - - &:disabled { - opacity: 0.4; - cursor: not-allowed; - } - } - - .spinner { - display: flex; - justify-content: center; - width: 100%; - color: #0a6ed1; - - > div { - width: 8px; - height: 8px; - margin: 6px; - border-radius: 100%; - background-color: currentColor; - animation: spinner-dots-pulse 1s ease infinite; - - &:nth-child(1) { - animation-delay: -0.2s; - } - - @keyframes spinner-dots-pulse { - 0%, - 100%, - 60% { - -webkit-transform: scale(1); - transform: scale(1); - } - 30% { - -webkit-transform: scale(2); - transform: scale(2); - } - } - } - } - - &.hidden { - display: none; - } - - // Top Bar - .asm-bar { - color: #fff; - background-color: #354a5f; - height: 48px; - display: flex; - padding: 0 2rem; - justify-content: space-between; - z-index: 1; - - &-branding { - display: flex; - align-items: center; - - .logo { - margin-inline-end: 8px; - } - - .asm-title { - font-size: 16px; - font-weight: 700; - } - } - - &-actions { - display: flex; - justify-content: flex-end; - align-items: center; - } - } - - > *:nth-child(2) { - padding: 1rem 2rem; - display: flex; - width: 100%; - } - - // Input styles - input { - outline: 0; - border: 1px solid #89919a; - color: #32363a; - background-color: #fff; - border-radius: 4px; - padding: 0 12px; - height: 36px; - - &:focus { - box-shadow: 0 0 0 1px #fafafa; - } - - &:hover { - border-color: #085caf; - } - &::placeholder { - color: #74777a; - font-style: italic; - } - } - - // Extra small devices (portrait phones, less than 576px) - @media (max-width: 575px) { - .asm-bar-branding .asm-title { - display: none; - } - - .asm-alert { - margin-top: 30px; - } - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.spec.ts b/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.spec.ts deleted file mode 100644 index 270884a5d52..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.spec.ts +++ /dev/null @@ -1,388 +0,0 @@ -import { - Component, - DebugElement, - EventEmitter, - Input, - Output, -} from '@angular/core'; -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { - AsmService, - AsmUi, - AuthService, - CsAgentAuthService, - GlobalMessageService, - I18nTestingModule, - RoutingService, - User, - UserService, -} from '@spartacus/core'; -import { Observable, of } from 'rxjs'; -import { AsmComponentService } from '../services/asm-component.service'; -import { AsmMainUiComponent } from './asm-main-ui.component'; - -class MockAuthService implements Partial { - isUserLoggedIn(): Observable { - return of(false); - } -} - -class MockCsAgentAuthService implements Partial { - authorizeCustomerSupportAgent(): Promise { - return Promise.resolve(); - } - isCustomerSupportAgentLoggedIn(): Observable { - return of(false); - } - getCustomerSupportAgentTokenLoading(): Observable { - return of(false); - } - startCustomerEmulationSession(_customerId: string) {} -} - -class MockUserService implements Partial { - get(): Observable { - return of({}); - } -} - -@Component({ - selector: 'cx-asm-toggle-ui', - template: '', -}) -class MockAsmToggleUiComponent {} - -@Component({ - selector: 'cx-asm-session-timer', - template: '', -}) -class MockAsmSessionTimerComponent {} - -@Component({ - selector: 'cx-customer-selection', - template: '', -}) -class MockCustomerSelectionComponent { - @Output() - submitEvent = new EventEmitter(); -} -@Component({ - selector: 'cx-csagent-login-form', - template: '', -}) -class MockCSAgentLoginFormComponent { - @Output() - submitEvent = new EventEmitter(); - @Input() - csAgentTokenLoading = false; -} -@Component({ - template: '', - selector: 'cx-customer-emulation', -}) -class MockCustomerEmulationComponent {} - -class MockGlobalMessageService implements Partial { - remove() {} - add() {} -} - -class MockRoutingService implements Partial { - go() {} -} - -class MockAsmComponentService { - logoutCustomerSupportAgentAndCustomer(): void {} - unload() {} - isCustomerEmulationSessionInProgress() { - return of(false); - } -} - -class MockAsmService implements Partial { - getAsmUiState(): Observable { - return of(mockAsmUi); - } -} - -const mockAsmUi: AsmUi = { - collapsed: false, -}; - -describe('AsmMainUiComponent', () => { - let component: AsmMainUiComponent; - let fixture: ComponentFixture; - let authService: AuthService; - let csAgentAuthService: CsAgentAuthService; - let userService: UserService; - let el: DebugElement; - let globalMessageService: GlobalMessageService; - let routingService: RoutingService; - let asmComponentService: AsmComponentService; - let asmService: AsmService; - - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [I18nTestingModule], - declarations: [ - AsmMainUiComponent, - MockAsmToggleUiComponent, - MockCSAgentLoginFormComponent, - MockCustomerSelectionComponent, - MockAsmSessionTimerComponent, - MockCustomerEmulationComponent, - ], - providers: [ - { provide: AuthService, useClass: MockAuthService }, - { provide: CsAgentAuthService, useClass: MockCsAgentAuthService }, - { provide: UserService, useClass: MockUserService }, - { provide: GlobalMessageService, useClass: MockGlobalMessageService }, - { provide: RoutingService, useClass: MockRoutingService }, - { provide: AsmComponentService, useClass: MockAsmComponentService }, - { provide: AsmService, useClass: MockAsmService }, - ], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(AsmMainUiComponent); - authService = TestBed.inject(AuthService); - csAgentAuthService = TestBed.inject(CsAgentAuthService); - userService = TestBed.inject(UserService); - globalMessageService = TestBed.inject(GlobalMessageService); - routingService = TestBed.inject(RoutingService); - asmComponentService = TestBed.inject(AsmComponentService); - asmService = TestBed.inject(AsmService); - component = fixture.componentInstance; - el = fixture.debugElement; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should call authorizeCustomerSupportAgent() on agent login form submit', () => { - spyOn(csAgentAuthService, 'authorizeCustomerSupportAgent').and.stub(); - - const userId = 'asagent'; - const password = 'password'; - component.loginCustomerSupportAgent({ userId, password }); - expect( - csAgentAuthService.authorizeCustomerSupportAgent - ).toHaveBeenCalledWith(userId, password); - }); - - it('should call logoutCustomerSupportAgentAndCustomer() on agent logout', () => { - spyOn( - asmComponentService, - 'logoutCustomerSupportAgentAndCustomer' - ).and.stub(); - - component.logout(); - - expect( - asmComponentService.logoutCustomerSupportAgentAndCustomer - ).toHaveBeenCalled(); - }); - - it('should call authService.startCustomerEmulationSession() when startCustomerEmulationSession() is called', () => { - spyOn(csAgentAuthService, 'startCustomerEmulationSession').and.stub(); - const testCustomerId = 'customerid1234567890'; - - component.startCustomerEmulationSession({ customerId: testCustomerId }); - - expect( - csAgentAuthService.startCustomerEmulationSession - ).toHaveBeenCalledWith(testCustomerId); - }); - - it('should not call authService.startCustomerEmulationSession() when customerId is undefined', () => { - spyOn(csAgentAuthService, 'startCustomerEmulationSession').and.stub(); - spyOn(globalMessageService, 'add').and.stub(); - - component.startCustomerEmulationSession({ customerId: undefined }); - - expect(globalMessageService.add).toHaveBeenCalled(); - expect( - csAgentAuthService.startCustomerEmulationSession - ).not.toHaveBeenCalled(); - }); - - it('should display the login form by default and when the collapse state is false', () => { - spyOn(csAgentAuthService, 'isCustomerSupportAgentLoggedIn').and.returnValue( - of(false) - ); - spyOn(authService, 'isUserLoggedIn').and.returnValue(of(false)); - component.ngOnInit(); - fixture.detectChanges(); - expect(el.query(By.css('cx-csagent-login-form'))).toBeTruthy(); - expect(el.query(By.css('cx-customer-selection'))).toBeFalsy(); - expect(el.query(By.css('cx-asm-session-timer'))).toBeFalsy(); - expect(el.query(By.css('cx-customer-emulation'))).toBeFalsy(); - }); - - it('should not display the login form by default and when the collapse state is true', () => { - spyOn(asmService, 'getAsmUiState').and.returnValue(of({ collapsed: true })); - spyOn(csAgentAuthService, 'isCustomerSupportAgentLoggedIn').and.returnValue( - of(false) - ); - spyOn(authService, 'isUserLoggedIn').and.returnValue(of(false)); - component.ngOnInit(); - fixture.detectChanges(); - expect(el.query(By.css('cx-csagent-login-form'))).toBeFalsy(); - expect(el.query(By.css('cx-customer-selection'))).toBeFalsy(); - expect(el.query(By.css('cx-asm-session-timer'))).toBeFalsy(); - expect(el.query(By.css('cx-customer-emulation'))).toBeFalsy(); - }); - - it('should display the customer selection state when an agent is signed in and when the collapse state is false', () => { - spyOn(csAgentAuthService, 'isCustomerSupportAgentLoggedIn').and.returnValue( - of(true) - ); - spyOn(authService, 'isUserLoggedIn').and.returnValue(of(false)); - spyOn(userService, 'get').and.returnValue(of({})); - component.ngOnInit(); - fixture.detectChanges(); - expect(el.query(By.css('cx-csagent-login-form'))).toBeFalsy(); - expect(el.query(By.css('cx-customer-selection'))).toBeTruthy(); - expect(el.query(By.css('cx-asm-session-timer'))).toBeTruthy(); - expect(el.query(By.css('cx-customer-emulation'))).toBeFalsy(); - expect(el.query(By.css('button[title="asm.logout"]'))).toBeTruthy(); - }); - - it('should not display the customer selection state when an agent is signed in and when the collapse state is true', () => { - spyOn(asmService, 'getAsmUiState').and.returnValue(of({ collapsed: true })); - spyOn(csAgentAuthService, 'isCustomerSupportAgentLoggedIn').and.returnValue( - of(true) - ); - spyOn(authService, 'isUserLoggedIn').and.returnValue(of(false)); - spyOn(userService, 'get').and.returnValue(of({})); - component.ngOnInit(); - fixture.detectChanges(); - expect(el.query(By.css('cx-csagent-login-form'))).toBeFalsy(); - expect(el.query(By.css('cx-customer-selection'))).toBeFalsy(); - expect(el.query(By.css('cx-asm-session-timer'))).toBeTruthy(); - expect(el.query(By.css('cx-customer-emulation'))).toBeFalsy(); - expect(el.query(By.css('button[title="asm.logout"]'))).toBeTruthy(); - }); - - it('should display customer emulation state when a customer is signed in and when the collapse state is false', () => { - const testUser = { uid: 'user@test.com', name: 'Test User' } as User; - spyOn(csAgentAuthService, 'isCustomerSupportAgentLoggedIn').and.returnValue( - of(true) - ); - spyOn(authService, 'isUserLoggedIn').and.returnValue(of(true)); - spyOn(userService, 'get').and.returnValue(of(testUser)); - component.ngOnInit(); - fixture.detectChanges(); - - expect(el.query(By.css('cx-customer-emulation'))).toBeTruthy(); - expect(el.query(By.css('cx-csagent-login-form'))).toBeFalsy(); - expect(el.query(By.css('cx-customer-selection'))).toBeFalsy(); - expect(el.query(By.css('cx-asm-session-timer'))).toBeTruthy(); - expect(el.query(By.css('button[title="asm.logout"]'))).toBeTruthy(); - }); - - it('should not display customer emulation state when a customer is signed in and when the collapse state is true', () => { - spyOn(asmService, 'getAsmUiState').and.returnValue(of({ collapsed: true })); - const testUser = { uid: 'user@test.com', name: 'Test User' } as User; - spyOn(csAgentAuthService, 'isCustomerSupportAgentLoggedIn').and.returnValue( - of(true) - ); - spyOn(authService, 'isUserLoggedIn').and.returnValue(of(true)); - spyOn(userService, 'get').and.returnValue(of(testUser)); - component.ngOnInit(); - fixture.detectChanges(); - - expect(el.query(By.css('cx-customer-emulation'))).toBeFalsy(); - expect(el.query(By.css('cx-csagent-login-form'))).toBeFalsy(); - expect(el.query(By.css('cx-customer-selection'))).toBeFalsy(); - expect(el.query(By.css('cx-asm-session-timer'))).toBeTruthy(); - expect(el.query(By.css('button[title="asm.logout"]'))).toBeTruthy(); - }); - - it('should redirect to home when starting a customer emulation session.', () => { - component['startingCustomerSession'] = true; - spyOn(csAgentAuthService, 'isCustomerSupportAgentLoggedIn').and.returnValue( - of(true) - ); - spyOn(authService, 'isUserLoggedIn').and.returnValue(of(true)); - spyOn( - asmComponentService, - 'isCustomerEmulationSessionInProgress' - ).and.returnValue(of(true)); - - spyOn(routingService, 'go').and.stub(); - spyOn(globalMessageService, 'remove').and.stub(); - component.ngOnInit(); - fixture.detectChanges(); - - expect(globalMessageService.remove).toHaveBeenCalled(); - expect(routingService.go).toHaveBeenCalled(); - }); - - it('should not redirect to home when not starting a customer emulation session.', () => { - component['startingCustomerSession'] = false; - spyOn(csAgentAuthService, 'isCustomerSupportAgentLoggedIn').and.returnValue( - of(true) - ); - spyOn(authService, 'isUserLoggedIn').and.returnValue(of(true)); - spyOn( - asmComponentService, - 'isCustomerEmulationSessionInProgress' - ).and.returnValue(of(true)); - - spyOn(routingService, 'go').and.stub(); - spyOn(globalMessageService, 'remove').and.stub(); - component.ngOnInit(); - fixture.detectChanges(); - - expect(globalMessageService.remove).not.toHaveBeenCalled(); - expect(routingService.go).not.toHaveBeenCalled(); - }); - - it('should not redirect to home when not handling a customer emulation session token.', () => { - component['startingCustomerSession'] = true; - spyOn(csAgentAuthService, 'isCustomerSupportAgentLoggedIn').and.returnValue( - of(true) - ); - spyOn(authService, 'isUserLoggedIn').and.returnValue(of(true)); - spyOn( - asmComponentService, - 'isCustomerEmulationSessionInProgress' - ).and.returnValue(of(false)); - - spyOn(routingService, 'go').and.stub(); - spyOn(globalMessageService, 'remove').and.stub(); - component.ngOnInit(); - fixture.detectChanges(); - - expect(globalMessageService.remove).not.toHaveBeenCalled(); - expect(routingService.go).not.toHaveBeenCalled(); - }); - - it('should hide the UI when the Close Asm button is clicked', () => { - component.ngOnInit(); - fixture.detectChanges(); - const submitBtn = fixture.debugElement.query( - By.css('button[title="asm.hideUi"]') - ); - submitBtn.nativeElement.dispatchEvent(new MouseEvent('click')); - expect(component.disabled).toEqual(true); - }); - - it('should unload ASM when the close button is clicked', () => { - spyOn(asmComponentService, 'unload').and.stub(); - component.ngOnInit(); - fixture.detectChanges(); - const submitBtn = fixture.debugElement.query( - By.css('button[title="asm.hideUi"]') - ); - submitBtn.nativeElement.dispatchEvent(new MouseEvent('click')); - expect(asmComponentService.unload).toHaveBeenCalled(); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.ts b/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.ts deleted file mode 100644 index ed61669a1f3..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-main-ui/asm-main-ui.component.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { - Component, - HostBinding, - OnInit, - ViewEncapsulation, -} from '@angular/core'; -import { - AsmService, - AuthService, - CsAgentAuthService, - GlobalMessageService, - GlobalMessageType, - RoutingService, - User, - UserService, -} from '@spartacus/core'; -import { Observable, of } from 'rxjs'; -import { map, switchMap, take } from 'rxjs/operators'; -import { AsmComponentService } from '../services/asm-component.service'; - -@Component({ - selector: 'cx-asm-main-ui', - templateUrl: './asm-main-ui.component.html', - styleUrls: ['./asm-main-ui.component.scss'], - encapsulation: ViewEncapsulation.None, -}) -export class AsmMainUiComponent implements OnInit { - customerSupportAgentLoggedIn$: Observable; - csAgentTokenLoading$: Observable; - customer$: Observable; - isCollapsed$: Observable; - - @HostBinding('class.hidden') disabled = false; - - private startingCustomerSession = false; - - constructor( - protected authService: AuthService, - protected csAgentAuthService: CsAgentAuthService, - protected userService: UserService, - protected asmComponentService: AsmComponentService, - protected globalMessageService: GlobalMessageService, - protected routingService: RoutingService, - protected asmService: AsmService - ) {} - - ngOnInit(): void { - this.customerSupportAgentLoggedIn$ = this.csAgentAuthService.isCustomerSupportAgentLoggedIn(); - this.csAgentTokenLoading$ = this.csAgentAuthService.getCustomerSupportAgentTokenLoading(); - this.customer$ = this.authService.isUserLoggedIn().pipe( - switchMap((isLoggedIn) => { - if (isLoggedIn) { - this.handleCustomerSessionStartRedirection(); - return this.userService.get(); - } else { - return of(undefined); - } - }) - ); - this.isCollapsed$ = this.asmService - .getAsmUiState() - .pipe(map((uiState) => uiState.collapsed)); - } - - private handleCustomerSessionStartRedirection(): void { - this.asmComponentService - .isCustomerEmulationSessionInProgress() - .pipe(take(1)) - .subscribe((isCustomerEmulated) => { - if (this.startingCustomerSession && isCustomerEmulated) { - this.startingCustomerSession = false; - this.globalMessageService.remove(GlobalMessageType.MSG_TYPE_ERROR); - this.routingService.go('/'); - } - }); - } - - loginCustomerSupportAgent({ - userId, - password, - }: { - userId: string; - password: string; - }): void { - this.csAgentAuthService.authorizeCustomerSupportAgent(userId, password); - } - - logout(): void { - this.asmComponentService.logoutCustomerSupportAgentAndCustomer(); - } - - startCustomerEmulationSession({ customerId }: { customerId: string }): void { - if (customerId) { - this.csAgentAuthService.startCustomerEmulationSession(customerId); - this.startingCustomerSession = true; - } else { - this.globalMessageService.add( - { key: 'asm.error.noCustomerId' }, - GlobalMessageType.MSG_TYPE_ERROR - ); - } - } - - hideUi(): void { - this.disabled = true; - this.asmComponentService.unload(); - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.html b/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.html deleted file mode 100644 index b71c528b5d3..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.html +++ /dev/null @@ -1,10 +0,0 @@ -{{ 'asm.agentSessionTimer.label' | cxTranslate }}: -{{ timeLeft | formatTimer }} - {{ 'asm.agentSessionTimer.minutes' | cxTranslate }} - diff --git a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.scss b/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.scss deleted file mode 100644 index 2f86d61e308..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.scss +++ /dev/null @@ -1,30 +0,0 @@ -cx-asm-session-timer { - display: flex; - align-items: center; - height: 16px; - - margin: 0 15px; - - .label { - margin: 0 6px; - @media (max-width: 575px) { - display: none; - } - } - .time { - font-weight: 600; - } - .reset { - margin: 0 15px; - cursor: pointer; - - width: 16px; - height: 16px; - - background: url("data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='%23d1e3ff' d='M14.9,7.5l-1,0.2c0.2,0.9,0.1,1.7-0.1,2.5c-0.3,1-0.8,2-1.5,2.7c-1.1,1.1-2.7,1.8-4.2,1.8 c-0.8,0-1.5-0.1-2.3-0.4c-1.5-0.6-2.7-1.8-3.3-3.3C2.1,10.2,2,9.5,2,8.7c0-1.6,0.7-3.1,1.8-4.3c0.7-0.8,1.7-1.3,2.7-1.5 c1-0.3,2-0.2,3,0l0,0v-1c-1-0.2-2.1-0.2-3.1,0C4.2,2.4,2.4,4,1.5,6.1C1.2,6.9,1,7.8,1,8.7c0,0.9,0.2,1.8,0.5,2.6 c0.4,0.9,0.9,1.7,1.5,2.3c0.7,0.7,1.4,1.2,2.3,1.5c0.8,0.3,1.7,0.5,2.6,0.5c0.9,0,1.8-0.2,2.6-0.5c2.1-0.9,3.7-2.7,4.2-5 C15,9.3,15,8.4,14.9,7.5z'/%3E%3Cpolygon fill='%23d1e3ff' points='11.5,2.8 9.2,4.5 9.7,0.5 '/%3E%3C/svg%3E%0A") - no-repeat center center; - - border: transparent; - background-color: transparent; - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.spec.ts b/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.spec.ts deleted file mode 100644 index f3a13c1667e..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.spec.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { ChangeDetectorRef, Pipe, PipeTransform } from '@angular/core'; -import { - waitForAsync, - ComponentFixture, - fakeAsync, - TestBed, - tick, -} from '@angular/core/testing'; -import { - AsmConfig, - I18nTestingModule, - OCC_USER_ID_ANONYMOUS, - RoutingService, - UserIdService, -} from '@spartacus/core'; -import { BehaviorSubject, Observable, of } from 'rxjs'; -import { AsmComponentService } from '../services/asm-component.service'; -import { AsmSessionTimerComponent } from './asm-session-timer.component'; -import createSpy = jasmine.createSpy; - -const MockAsmConfig: AsmConfig = { - asm: { - agentSessionTimer: { - startingDelayInSeconds: 1, - }, - }, -}; - -class MockUserIdService implements Partial { - getUserId(): Observable { - return of(''); - } -} - -class MockAsmComponentService implements Partial { - logoutCustomerSupportAgentAndCustomer(): void {} -} -class MockRoutingService implements Partial { - go() {} - isNavigating() { - return of(false); - } -} - -@Pipe({ - name: 'formatTimer', -}) -class MockFormatTimerPipe implements PipeTransform { - transform() {} -} - -describe('AsmSessionTimerComponent', () => { - let component: AsmSessionTimerComponent; - let fixture: ComponentFixture; - let config: AsmConfig; - let asmComponentService: AsmComponentService; - let routingService: RoutingService; - let userIdService: UserIdService; - - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [I18nTestingModule], - declarations: [AsmSessionTimerComponent, MockFormatTimerPipe], - providers: [ - { - provide: ChangeDetectorRef, - useValue: { markForCheck: createSpy('markForCheck') }, - }, - { provide: AsmConfig, useValue: MockAsmConfig }, - { provide: AsmComponentService, useClass: MockAsmComponentService }, - { provide: RoutingService, useClass: MockRoutingService }, - { provide: UserIdService, useClass: MockUserIdService }, - ], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(AsmSessionTimerComponent); - config = TestBed.inject(AsmConfig); - asmComponentService = TestBed.inject(AsmComponentService); - routingService = TestBed.inject(RoutingService); - userIdService = TestBed.inject(UserIdService); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should logout when time left is zero.', fakeAsync(() => { - config.asm.agentSessionTimer.startingDelayInSeconds = 1; - spyOn( - asmComponentService, - 'logoutCustomerSupportAgentAndCustomer' - ).and.stub(); - component.ngOnInit(); - tick(2000); - expect( - asmComponentService.logoutCustomerSupportAgentAndCustomer - ).toHaveBeenCalled(); - component.ngOnDestroy(); - })); - - it('should not call logout when there is some time left.', fakeAsync(() => { - config.asm.agentSessionTimer.startingDelayInSeconds = 10; - spyOn( - asmComponentService, - 'logoutCustomerSupportAgentAndCustomer' - ).and.stub(); - component.ngOnInit(); - tick(1000); - expect( - asmComponentService.logoutCustomerSupportAgentAndCustomer - ).not.toHaveBeenCalled(); - component.ngOnDestroy(); - })); - - it('should reset the time left when user navigates on a new page.', () => { - spyOn(component, 'resetOnCustomerSessionChange').and.stub(); - spyOn(component, 'resetTimer').and.callThrough(); - spyOn(routingService, 'isNavigating').and.returnValue(of(true)); - component.ngOnInit(); - expect(component.resetTimer).toHaveBeenCalled(); - }); - - it('should not reset the time left when user is not navigating to a new page', () => { - spyOn(component, 'resetOnCustomerSessionChange').and.stub(); - spyOn(component, 'resetTimer').and.callThrough(); - spyOn(routingService, 'isNavigating').and.returnValue(of(false)); - component.ngOnInit(); - expect(component.resetTimer).not.toHaveBeenCalled(); - }); - - it('should use start delay from the config', () => { - config.asm.agentSessionTimer.startingDelayInSeconds = 632; - component.ngOnInit(); - const result = component['getTimerStartDelayInSeconds'](); - expect(result).toBe(config.asm.agentSessionTimer.startingDelayInSeconds); - }); - it('should use a maximum start delay', () => { - config.asm.agentSessionTimer.startingDelayInSeconds = 1000000; - component.ngOnInit(); - const result = component['getTimerStartDelayInSeconds'](); - expect(result).toBe(component['maxStartDelayInSeconds']); - }); - - it('should reset the time left when agent starts a new customer session', () => { - spyOn(component, 'resetOnNavigate').and.stub(); - const occUserId$: BehaviorSubject = new BehaviorSubject( - OCC_USER_ID_ANONYMOUS - ); - spyOn(component, 'resetTimer').and.callThrough(); - spyOn(userIdService, 'getUserId').and.returnValue(occUserId$); - spyOn(routingService, 'isNavigating').and.returnValue(of(false)); - component.ngOnInit(); // reset 1, initial value anonymous. - occUserId$.next('customer01'); // reset 2, staring an emulation session. - occUserId$.next('customer01'); // no reset, simulates token resfresh - occUserId$.next(OCC_USER_ID_ANONYMOUS); // reset 3, end customer emulation session - expect(component.resetTimer).toHaveBeenCalledTimes(3); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.ts b/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.ts deleted file mode 100644 index e71fc652e63..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/asm-session-timer.component.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { - ChangeDetectorRef, - Component, - OnDestroy, - OnInit, - ViewEncapsulation, -} from '@angular/core'; -import { AsmConfig, RoutingService, UserIdService } from '@spartacus/core'; -import { Subscription } from 'rxjs'; -import { distinctUntilChanged } from 'rxjs/operators'; -import { AsmComponentService } from '../services/asm-component.service'; - -@Component({ - selector: 'cx-asm-session-timer', - templateUrl: './asm-session-timer.component.html', - styleUrls: ['./asm-session-timer.component.scss'], - encapsulation: ViewEncapsulation.None, -}) -export class AsmSessionTimerComponent implements OnInit, OnDestroy { - private subscriptions = new Subscription(); - private interval: any; - private maxStartDelayInSeconds = 60000; - timeLeft: number; - - constructor( - private config: AsmConfig, - private asmComponentService: AsmComponentService, - private routingService: RoutingService, - private changeDetectorRef: ChangeDetectorRef, - private userIdService: UserIdService - ) {} - - ngOnInit(): void { - this.timeLeft = this.getTimerStartDelayInSeconds(); - this.interval = setInterval(() => { - if (this.timeLeft > 0) { - this.timeLeft--; - } else { - clearInterval(this.interval); - this.asmComponentService.logoutCustomerSupportAgentAndCustomer(); - } - this.changeDetectorRef.markForCheck(); - }, 1000); - - this.resetOnNavigate(); - this.resetOnCustomerSessionChange(); - } - - private resetOnNavigate(): void { - this.subscriptions.add( - this.routingService.isNavigating().subscribe((isNavigating) => { - if (isNavigating) { - this.resetTimer(); - } - }) - ); - } - - private resetOnCustomerSessionChange(): void { - this.subscriptions.add( - this.userIdService - .getUserId() - .pipe(distinctUntilChanged()) - .subscribe(() => this.resetTimer()) - ); - } - - resetTimer(): void { - if (this.timeLeft > 0) { - this.timeLeft = this.getTimerStartDelayInSeconds(); - } - } - - private getTimerStartDelayInSeconds(): number { - if ( - this.config.asm.agentSessionTimer.startingDelayInSeconds > - this.maxStartDelayInSeconds - ) { - return this.maxStartDelayInSeconds; - } else { - return this.config.asm.agentSessionTimer.startingDelayInSeconds; - } - } - ngOnDestroy(): void { - this.subscriptions.unsubscribe(); - if (this.interval) { - clearInterval(this.interval); - } - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/format-timer.pipe.spec.ts b/projects/storefrontlib/src/cms-components/asm/asm-session-timer/format-timer.pipe.spec.ts deleted file mode 100644 index c7640defd48..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/format-timer.pipe.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { FormatTimerPipe } from './format-timer.pipe'; - -describe('FormatTimerPipe', () => { - let pipe: FormatTimerPipe; - - beforeEach(() => { - pipe = new FormatTimerPipe(); - }); - - it('create an instance', () => { - expect(pipe).toBeTruthy(); - }); - it('format zero seconds', () => { - expect(pipe.transform(0)).toBe('00:00'); - }); - it('format one digit seconds', () => { - expect(pipe.transform(7)).toBe('00:07'); - }); - it('format two digit seconds', () => { - expect(pipe.transform(15)).toBe('00:15'); - }); - it('format one digit minutes', () => { - expect(pipe.transform(77)).toBe('01:17'); - }); - it('format two digit minutes', () => { - expect(pipe.transform(1267)).toBe('21:07'); - }); - it('format two digit minutes', () => { - expect(pipe.transform(1267)).toBe('21:07'); - }); - it('handle negative number', () => { - expect(pipe.transform(-7)).toBe('00:00'); - }); - it('handle negative number', () => { - expect(pipe.transform(6663)).toBe('111:03'); - }); - it('handle negative number', () => { - expect(pipe.transform(66664)).toBe('1111:04'); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/format-timer.pipe.ts b/projects/storefrontlib/src/cms-components/asm/asm-session-timer/format-timer.pipe.ts deleted file mode 100644 index e014036a317..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-session-timer/format-timer.pipe.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Pipe, PipeTransform } from '@angular/core'; - -@Pipe({ - name: 'formatTimer', -}) -export class FormatTimerPipe implements PipeTransform { - transform(totalSeconds: number): string { - if (totalSeconds < 0) { - totalSeconds = 0; - } - const minutes: number = Math.floor(totalSeconds / 60); - const seconds: number = totalSeconds % 60; - let zeroPaddedMinutes: string; - if (minutes < 10) { - zeroPaddedMinutes = ('00' + minutes).slice(-2); - } else { - zeroPaddedMinutes = minutes + ''; - } - const zeroPaddedSeconds: string = ('00' + seconds).slice(-2); - return `${zeroPaddedMinutes}:${zeroPaddedSeconds}`; - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.html b/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.html deleted file mode 100644 index fc105d7dfc8..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - {{ 'asm.toggleUi.collapse' | cxTranslate }} - - - {{ 'asm.toggleUi.expand' | cxTranslate }} - - diff --git a/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.scss b/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.scss deleted file mode 100644 index 09d8c72caed..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.scss +++ /dev/null @@ -1,37 +0,0 @@ -cx-asm-toggle-ui { - cursor: pointer; - display: flex; - align-items: center; - - height: 16px; - margin: 0 15px; - - .toggleUi { - display: inherit; - align-items: inherit; - - .label { - margin-inline-start: 5px; - - @media (max-width: 575px) { - display: none; - } - } - - .collapseIcon, - .expandIcon { - width: 16px; - height: 16px; - } - - .collapseIcon { - background: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='chevron-circle-up' class='svg-inline--fa fa-chevron-circle-up fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23d1e3ff' d='M8 256C8 119 119 8 256 8s248 111 248 248-111 248-248 248S8 393 8 256zm231-113.9L103.5 277.6c-9.4 9.4-9.4 24.6 0 33.9l17 17c9.4 9.4 24.6 9.4 33.9 0L256 226.9l101.6 101.6c9.4 9.4 24.6 9.4 33.9 0l17-17c9.4-9.4 9.4-24.6 0-33.9L273 142.1c-9.4-9.4-24.6-9.4-34 0z'%3E%3C/path%3E%3C/svg%3E") - center center no-repeat; - } - - .expandIcon { - background: url("data:image/svg+xml,%3Csvg aria-hidden='true' focusable='false' data-prefix='fas' data-icon='chevron-circle-down' class='svg-inline--fa fa-chevron-circle-down fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath fill='%23d1e3ff' d='M504 256c0 137-111 248-248 248S8 393 8 256 119 8 256 8s248 111 248 248zM273 369.9l135.5-135.5c9.4-9.4 9.4-24.6 0-33.9l-17-17c-9.4-9.4-24.6-9.4-33.9 0L256 285.1 154.4 183.5c-9.4-9.4-24.6-9.4-33.9 0l-17 17c-9.4 9.4-9.4 24.6 0 33.9L239 369.9c9.4 9.4 24.6 9.4 34 0z'%3E%3C/path%3E%3C/svg%3E") - center center no-repeat; - } - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.spec.ts b/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.spec.ts deleted file mode 100644 index 764a35b5bf9..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { DebugElement } from '@angular/core'; -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { AsmService, AsmUi, I18nTestingModule } from '@spartacus/core'; -import { Observable, of } from 'rxjs'; -import { AsmToggleUiComponent } from './asm-toggle-ui.component'; - -class MockAsmService { - getAsmUiState(): Observable { - return of(mockAsmUi); - } - - updateAsmUiState(_asmUi): void {} -} - -const mockAsmUi: AsmUi = { - collapsed: false, -}; - -describe('AsmToggleuUiComponent', () => { - let component: AsmToggleUiComponent; - let fixture: ComponentFixture; - let asmService: AsmService; - let el: DebugElement; - - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [I18nTestingModule], - declarations: [AsmToggleUiComponent], - providers: [{ provide: AsmService, useClass: MockAsmService }], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(AsmToggleUiComponent); - component = fixture.componentInstance; - asmService = TestBed.inject(AsmService); - el = fixture.debugElement; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should display expandIcon when AsmUi collapse state is true', () => { - spyOn(asmService, 'getAsmUiState').and.returnValue(of({ collapsed: true })); - - component.ngOnInit(); - fixture.detectChanges(); - - expect(el.query(By.css('.expandIcon'))).toBeTruthy(); - expect(el.query(By.css('.collapseIcon'))).toBeFalsy(); - }); - - it('should display collapseIcon when AsmUi collapse state is false', () => { - component.ngOnInit(); - fixture.detectChanges(); - - expect(el.query(By.css('.expandIcon'))).toBeFalsy(); - expect(el.query(By.css('.collapseIcon'))).toBeTruthy(); - }); - - it('should call toggleUi() and toggle the collapse value', () => { - spyOn(asmService, 'updateAsmUiState').and.stub(); - - el.query(By.css('.toggleUi')).nativeElement.dispatchEvent( - new MouseEvent('click') - ); - - fixture.detectChanges(); - - expect(asmService.updateAsmUiState).toHaveBeenCalledWith({ - collapsed: true, - }); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.ts b/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.ts deleted file mode 100644 index fd8258e5cf7..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm-toggle-ui/asm-toggle-ui.component.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; -import { AsmService } from '@spartacus/core'; -import { Subscription } from 'rxjs'; - -@Component({ - selector: 'cx-asm-toggle-ui', - templateUrl: './asm-toggle-ui.component.html', - styleUrls: ['./asm-toggle-ui.component.scss'], - encapsulation: ViewEncapsulation.None, -}) -export class AsmToggleUiComponent implements OnInit, OnDestroy { - private subscription = new Subscription(); - isCollapsed: boolean; - - constructor(protected asmService: AsmService) {} - - ngOnInit(): void { - this.subscription.add( - this.asmService.getAsmUiState().subscribe((uiState) => { - this.isCollapsed = uiState.collapsed; - }) - ); - } - - toggleUi(): void { - this.asmService.updateAsmUiState({ collapsed: !this.isCollapsed }); - } - - ngOnDestroy(): void { - this.subscription.unsubscribe(); - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/asm.module.ts b/projects/storefrontlib/src/cms-components/asm/asm.module.ts deleted file mode 100644 index 39cc65b3aa7..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/asm.module.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { ReactiveFormsModule } from '@angular/forms'; -import { - AsmModule as AsmCoreModule, - I18nModule, - provideConfig, -} from '@spartacus/core'; -import { FormErrorsModule } from '../../shared/index'; -import { AsmLoaderModule } from './asm-loader.module'; -import { AsmMainUiComponent } from './asm-main-ui/asm-main-ui.component'; -import { AsmSessionTimerComponent } from './asm-session-timer/asm-session-timer.component'; -import { FormatTimerPipe } from './asm-session-timer/format-timer.pipe'; -import { AsmToggleUiComponent } from './asm-toggle-ui/asm-toggle-ui.component'; -import { CSAgentLoginFormComponent } from './csagent-login-form/csagent-login-form.component'; -import { CustomerEmulationComponent } from './customer-emulation/customer-emulation.component'; -import { CustomerSelectionComponent } from './customer-selection/customer-selection.component'; -import { defaultAsmLayoutConfig } from './default-asm-layout.config'; - -/** - * @deprecated since 3.2, use asm lib instead - */ -@NgModule({ - imports: [ - CommonModule, - ReactiveFormsModule, - I18nModule, - AsmCoreModule.forRoot(), - AsmLoaderModule, - FormErrorsModule, - ], - declarations: [ - AsmMainUiComponent, - CSAgentLoginFormComponent, - CustomerSelectionComponent, - AsmSessionTimerComponent, - FormatTimerPipe, - CustomerEmulationComponent, - AsmToggleUiComponent, - ], - providers: [provideConfig(defaultAsmLayoutConfig)], - entryComponents: [AsmMainUiComponent], -}) -export class AsmModule {} diff --git a/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.html b/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.html deleted file mode 100644 index 48e17973f12..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.html +++ /dev/null @@ -1,39 +0,0 @@ -
- - - - -
- -
-
-
-
-
diff --git a/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.scss b/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.scss deleted file mode 100644 index d70e4a524e8..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.scss +++ /dev/null @@ -1,36 +0,0 @@ -cx-csagent-login-form { - form { - display: flex; - width: 100%; - - @media (max-width: 575px) { - flex-direction: column; - } - - label { - margin: 0 0 15px; - min-width: auto; - - @media (min-width: 575px) { - margin-inline-end: 15px; - margin-top: 0; - margin-bottom: 0; - margin-inline-start: 0; - min-width: 15rem; - } - - input { - width: 100%; - } - } - } - - button[type='submit'] { - color: #fff; - border-color: #0a6ed1; - background-color: #0a6ed1; - &:hover { - background-color: #085caf; - } - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.spec.ts b/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.spec.ts deleted file mode 100644 index e7a48232453..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.spec.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { DebugElement } from '@angular/core'; -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { AbstractControl, ReactiveFormsModule } from '@angular/forms'; -import { By } from '@angular/platform-browser'; -import { I18nTestingModule } from '@spartacus/core'; -import { FormErrorsModule } from '../../../shared/index'; -import * as testUtils from '../../../shared/utils/forms/form-test-utils'; -import { CSAgentLoginFormComponent } from './csagent-login-form.component'; - -describe('CSAgentLoginFormComponent', () => { - let component: CSAgentLoginFormComponent; - let fixture: ComponentFixture; - let userIdFormControl: AbstractControl; - let passwordFormControl: AbstractControl; - let el: DebugElement; - - const validUserId = 'asagent'; - const validPassword = 'testPass123!'; - - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ReactiveFormsModule, I18nTestingModule, FormErrorsModule], - declarations: [CSAgentLoginFormComponent], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(CSAgentLoginFormComponent); - component = fixture.componentInstance; - el = fixture.debugElement; - fixture.detectChanges(); - - userIdFormControl = component.csAgentLoginForm.controls['userId']; - passwordFormControl = component.csAgentLoginForm.controls['password']; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - describe('onSubmit() ', () => { - it('should be called when submit button is clicked', () => { - spyOn(component, 'onSubmit').and.stub(); - - testUtils.clickSubmit(fixture); - - expect(component.onSubmit).toHaveBeenCalled(); - }); - - it('should not emit submitted event if the form is not valid', () => { - spyOn(component, 'onSubmit').and.stub(); - spyOn(component.submitEvent, 'emit').and.stub(); - - component.onSubmit(); - - expect(component.csAgentLoginForm.valid).toBeFalsy(); - expect(component.onSubmit).toHaveBeenCalled(); - expect(component.submitEvent.emit).not.toHaveBeenCalled(); - }); - - it('should emit submitted event when the form is valid', () => { - spyOn(component.submitEvent, 'emit').and.stub(); - - userIdFormControl.setValue(validUserId); - passwordFormControl.setValue(validPassword); - fixture.detectChanges(); - component.onSubmit(); - - expect(component.csAgentLoginForm.valid).toBeTruthy(); - expect(component.submitEvent.emit).toHaveBeenCalled(); - }); - }); - - it('should display spinner when login is running', () => { - component.csAgentTokenLoading = true; - component.ngOnInit(); - fixture.detectChanges(); - - expect(el.query(By.css('div.spinner'))).toBeTruthy(); - expect(el.query(By.css('form'))).toBeFalsy(); - }); - it('should not display spinner when login is not running', () => { - component.csAgentTokenLoading = false; - component.ngOnInit(); - fixture.detectChanges(); - - expect(el.query(By.css('div.spinner'))).toBeFalsy(); - expect(el.query(By.css('form'))).toBeTruthy(); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.ts b/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.ts deleted file mode 100644 index 54a03fb81cf..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/csagent-login-form/csagent-login-form.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { - Component, - EventEmitter, - Input, - OnInit, - Output, - ViewEncapsulation, -} from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; - -@Component({ - selector: 'cx-csagent-login-form', - templateUrl: './csagent-login-form.component.html', - styleUrls: ['./csagent-login-form.component.scss'], - encapsulation: ViewEncapsulation.None, -}) -export class CSAgentLoginFormComponent implements OnInit { - csAgentLoginForm: FormGroup; - - @Input() - csAgentTokenLoading = false; - - @Output() - submitEvent = new EventEmitter<{ userId: string; password: string }>(); - - constructor(private fb: FormBuilder) {} - - ngOnInit(): void { - this.csAgentLoginForm = this.fb.group({ - userId: ['', [Validators.required]], - password: ['', [Validators.required]], - }); - } - - onSubmit(): void { - if (this.csAgentLoginForm.valid) { - this.submitEvent.emit({ - userId: this.csAgentLoginForm.get('userId').value, - password: this.csAgentLoginForm.get('password').value, - }); - } else { - this.csAgentLoginForm.markAllAsTouched(); - } - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.html b/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.html deleted file mode 100644 index d931599fac9..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - diff --git a/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.scss b/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.scss deleted file mode 100644 index 134e1936b87..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.scss +++ /dev/null @@ -1,47 +0,0 @@ -cx-customer-emulation { - display: flex; - - @media (max-width: 575px) { - flex-direction: column; - > * { - margin-bottom: 12px; - } - } - - @media (min-width: 575px) { - input { - flex: 1; - } - } - button { - @media (min-width: 575px) { - margin-inline-start: 8px; - } - - padding-inline-start: 35px; - color: #bb0000; - border-color: #bb0000; - - background: url("data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='%23bb0000' d='M14.8,8c0-3.7-3-6.8-6.8-6.8S1.3,4.2,1.3,8s3,6.8,6.8,6.8S14.8,11.7,14.8,8z M2.6,8c0-3,2.4-5.5,5.5-5.5S13.5,5,13.5,8 s-2.4,5.5-5.5,5.5S2.6,11,2.6,8z M10.7,5.8v4.4c0,0.2-0.2,0.4-0.4,0.4H5.9c-0.2,0-0.4-0.2-0.4-0.4V5.8c0-0.2,0.2-0.4,0.4-0.4h4.4 C10.5,5.4,10.7,5.6,10.7,5.8z'/%3E%3C/svg%3E%0A") - no-repeat 10px center; - - &:hover { - background: url("data:image/svg+xml,%0A%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath fill='white' d='M14.8,8c0-3.7-3-6.8-6.8-6.8S1.3,4.2,1.3,8s3,6.8,6.8,6.8S14.8,11.7,14.8,8z M2.6,8c0-3,2.4-5.5,5.5-5.5S13.5,5,13.5,8 s-2.4,5.5-5.5,5.5S2.6,11,2.6,8z M10.7,5.8v4.4c0,0.2-0.2,0.4-0.4,0.4H5.9c-0.2,0-0.4-0.2-0.4-0.4V5.8c0-0.2,0.2-0.4,0.4-0.4h4.4 C10.5,5.4,10.7,5.6,10.7,5.8z'/%3E%3C/svg%3E%0A") - no-repeat 10px center #bb0000; - - color: #fff; - fill: #fff; - } - } -} - -//Session-in-progress alert -.asm-alert { - padding: 9px 12px; - border-radius: 4px; - border: 1px solid #89919a; - background-color: #f4f4f4; - color: #32363a; - text-align: center; - flex: 1; -} diff --git a/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.spec.ts b/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.spec.ts deleted file mode 100644 index abb81f9990e..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { DebugElement } from '@angular/core'; -import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { I18nTestingModule, User, UserService } from '@spartacus/core'; -import { Observable, of } from 'rxjs'; -import { AsmComponentService } from '../services/asm-component.service'; -import { CustomerEmulationComponent } from './customer-emulation.component'; - -class MockUserService { - get(): Observable { - return of({}); - } -} - -class MockAsmComponentService { - logoutCustomer(): void {} - isCustomerEmulationSessionInProgress(): Observable { - return of(true); - } -} - -describe('CustomerEmulationComponent', () => { - let component: CustomerEmulationComponent; - let fixture: ComponentFixture; - let userService: UserService; - let asmComponentService: AsmComponentService; - let el: DebugElement; - - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [I18nTestingModule], - declarations: [CustomerEmulationComponent], - providers: [ - { provide: UserService, useClass: MockUserService }, - { provide: AsmComponentService, useClass: MockAsmComponentService }, - ], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(CustomerEmulationComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - userService = TestBed.inject(UserService); - asmComponentService = TestBed.inject(AsmComponentService); - el = fixture.debugElement; - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should display user info during customer emulation.', () => { - const testUser = { uid: 'user@test.com', name: 'Test User' } as User; - spyOn(userService, 'get').and.returnValue(of(testUser)); - component.ngOnInit(); - fixture.detectChanges(); - - expect( - el.query(By.css('input[formcontrolname="customer"]')).nativeElement - .placeholder - ).toEqual(`${testUser.name}, ${testUser.uid}`); - expect(el.query(By.css('dev.fd-alert'))).toBeFalsy(); - }); - - it('should display alert message dusring regular customer session.', () => { - const testUser = { uid: 'user@test.com', name: 'Test User' } as User; - spyOn(userService, 'get').and.returnValue(of(testUser)); - spyOn( - asmComponentService, - 'isCustomerEmulationSessionInProgress' - ).and.returnValue(of(false)); - - component.ngOnInit(); - fixture.detectChanges(); - - expect(el.query(By.css('input[formcontrolname="customer"]'))).toBeFalsy(); - expect(el.query(By.css('div.asm-alert'))).toBeTruthy(); - }); - - it("should call logoutCustomer() on 'End Session' button click", () => { - //customer login - const testUser = { uid: 'user@test.com', name: 'Test User' } as User; - spyOn(userService, 'get').and.returnValue(of(testUser)); - - component.ngOnInit(); - fixture.detectChanges(); - - //Click button - const endSessionButton = fixture.debugElement.query(By.css('button')); - spyOn(asmComponentService, 'logoutCustomer').and.stub(); - endSessionButton.nativeElement.click(); - - //assert - expect(asmComponentService.logoutCustomer).toHaveBeenCalled(); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.ts b/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.ts deleted file mode 100644 index bfd6fc9fa5a..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/customer-emulation/customer-emulation.component.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; -import { User, UserService } from '@spartacus/core'; -import { Observable, Subscription } from 'rxjs'; -import { AsmComponentService } from '../services/asm-component.service'; - -@Component({ - selector: 'cx-customer-emulation', - templateUrl: './customer-emulation.component.html', - styleUrls: ['./customer-emulation.component.scss'], - encapsulation: ViewEncapsulation.None, -}) -export class CustomerEmulationComponent implements OnInit, OnDestroy { - customer: User; - isCustomerEmulationSessionInProgress$: Observable; - private subscription = new Subscription(); - - constructor( - protected asmComponentService: AsmComponentService, - protected userService: UserService - ) {} - - ngOnInit() { - this.subscription.add( - this.userService.get().subscribe((user) => (this.customer = user)) - ); - this.isCustomerEmulationSessionInProgress$ = this.asmComponentService.isCustomerEmulationSessionInProgress(); - } - - logoutCustomer() { - this.asmComponentService.logoutCustomer(); - } - - ngOnDestroy(): void { - this.subscription.unsubscribe(); - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.html b/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.html deleted file mode 100644 index cbf0fc9dc96..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.html +++ /dev/null @@ -1,45 +0,0 @@ -
- - -
- -
- - -
- -
-
-
-
-
-
-
diff --git a/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.scss b/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.scss deleted file mode 100644 index 86fa54e99d9..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.scss +++ /dev/null @@ -1,105 +0,0 @@ -cx-customer-selection { - position: relative; - - form { - display: flex; - width: 100%; - - @media (max-width: 575px) { - flex-direction: column; - } - - label { - margin: 0 0 15px; - min-width: auto; - - @media (min-width: 575px) { - margin-inline-end: 15px; - min-width: 20rem; - } - - input { - width: 100%; - } - } - - button[type='submit'] { - border-color: #0a7e3e; - - color: #fff; - padding-inline-start: 35px; - // TODO: replace below base64 with some light SVG - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAKtmlDQ1BEaXNwbGF5AABIx62Wd1BT+RbHf/fe9EILICAl9N6lSwk9dOkgKiEJJJQYEoKIDZHFFVwLKiKgrugiRcFGkbUgFiwsgg2sC7IoqOtiwYbKu8Aj7L6Z98ebeWfm3N9nzpzf+Z1z7/3NfAGgApZQmA7LAZAhyBKF+3nSY+Pi6fghAAEYEIE+cGaxxUJGWFgQQG12/ad9uIdmo3bbfKoW+N9MnsMVswGAwlBO4ojZGSifQv0ZWyjKAgCpROO6K7KEU9yOsqIIbRDlO1OcMsMjU5w0w1+ncyLDvQDAoFMRKCyWKAUAijoap2ezU9A6lIUoWwk4fAHKU/26sXksDspHUDbLyFg+xf0oGyX9rU7KP2omSWuyWClSnpll2gjefLEwnbUS/L8tI10ye4YB6hSeyD8cXWXQd9aftjxQyoKkkNBZ5nOm86eZJ/GPmmW22Ct+ljks70Dp3vSQoFlO5vsypXWymJGzzBX7RMyyaHm49KxkkRdjllmiuXMlaVHSOI/LlNbP5UXGzHI2PzpklsVpEYFzOV7SuEgSLu2fK/DznDvXVzp7hvhv8/KZ0r1ZvEh/6eysuf65AsZcTXGstDcO19tnLidKmi/M8pSeJUwPk+Zz0/2kcXF2hHRvFvpDzu0Nk77DVFZA2CwDfxAG6MAGWIEcwAcgi5uTNTWE13LhShE/hZdFZ6C3i0tnCtgWZnQbK2snAKbu6syv8K5/+g5CyoS5WGY+AE7ofUCC52JLFwNwvAEAhdC5mMFn9Mqg3+DsdrZElD0Tw0w9sIAEZIEiUAWaQBcYAXO0O3vgAjyADwgAoSASxIGlgA14IAOIwAqwGqwHhaAYbAO7QDnYDw6CGnAUnAAt4Ay4AK6AG6AH3AUPwQAYBi/BGPgAJiAIwkNUiAapQlqQPmQK2UCOkBvkAwVB4VAclAilQAJIAq2GNkDFUAlUDh2AaqHj0GnoAnQN6oXuQ4PQKPQW+gIjMAVWhDVgA9gSdoQZcCAcCS+BU+BMOBcugLfAZXAVfARuhi/AN+C78AD8Eh5HAEJGlBFtxBxxRLyQUCQeSUZEyFqkCClFqpAGpA3pRG4jA8gr5DMGh6Fh6BhzjAvGHxOFYWMyMWsxmzHlmBpMM+YS5jZmEDOG+Y6lYtWxplhnLBMbi03BrsAWYkux1dgm7GXsXeww9gMOh1PGGeIccP64OFwqbhVuM24vrhHXjuvFDeHG8Xi8Kt4U74oPxbPwWfhC/B78Efx5/C38MP4TgUzQItgQfAnxBAEhn1BKqCOcI9wiPCdMEOWI+kRnYiiRQ1xJ3Eo8RGwj3iQOEydI8iRDkispkpRKWk8qIzWQLpMekd6RyWQdshN5EZlPziOXkY+Rr5IHyZ8pChQTihclgSKhbKEcprRT7lPeUalUA6oHNZ6aRd1CraVepD6hfpKhyVjIMGU4MutkKmSaZW7JvJYlyurLMmSXyubKlsqelL0p+0qOKGcg5yXHklsrVyF3Wq5PblyeJm8tHyqfIb9Zvk7+mvyIAl7BQMFHgaNQoHBQ4aLCEA2h6dK8aGzaBtoh2mXasCJO0VCRqZiqWKx4VLFbcUxJQWmBUrRSjlKF0lmlAWVE2UCZqZyuvFX5hPI95S/zNOYx5nHnbZrXMO/WvI8q81U8VLgqRSqNKndVvqjSVX1U01S3q7aoPlbDqJmoLVJbobZP7bLaq/mK813ms+cXzT8x/4E6rG6iHq6+Sv2gepf6uIamhp+GUGOPxkWNV5rKmh6aqZo7Nc9pjmrRtNy0+Fo7tc5rvaAr0Rn0dHoZ/RJ9TFtd219bon1Au1t7QsdQJ0onX6dR57EuSddRN1l3p26H7piell6w3mq9er0H+kR9R32e/m79Tv2PBoYGMQYbDVoMRgxVDJmGuYb1ho+MqEbuRplGVUZ3jHHGjsZpxnuNe0xgEzsTnkmFyU1T2NTelG+617TXDGvmZCYwqzLrM6eYM8yzzevNBy2ULYIs8i1aLF5b6lnGW2637LT8bmVnlW51yOqhtYJ1gHW+dZv1WxsTG7ZNhc0dW6qtr+0621bbNwtMF3AX7FvQb0ezC7bbaNdh983ewV5k32A/6qDnkOhQ6dDnqOgY5rjZ8aoT1snTaZ3TGafPzvbOWc4nnP9yMXdJc6lzGVlouJC78NDCIVcdV5brAdcBN7pbotvPbgPu2u4s9yr3px66HhyPao/nDGNGKuMI47WnlafIs8nzo5ez1xqvdm/E28+7yLvbR8Enyqfc54mvjm+Kb73vmJ+d3yq/dn+sf6D/dv8+pgaTzaxljgU4BKwJuBRICYwILA98GmQSJApqC4aDA4J3BD8K0Q8RhLSEglBm6I7Qx2GGYZlhvy7CLQpbVLHoWbh1+OrwzghaxLKIuogPkZ6RWyMfRhlFSaI6omWjE6Jroz/GeMeUxAzEWsauib0RpxbHj2uNx8dHx1fHjy/2Wbxr8XCCXUJhwr0lhktyllxbqrY0fenZZbLLWMtOJmITYxLrEr+yQllVrPEkZlJl0hjbi72b/ZLjwdnJGeW6cku4z5Ndk0uSR1JcU3akjPLceaW8V3wvfjn/Tap/6v7Uj2mhaYfTJtNj0hszCBmJGacFCoI0waXlmstzlvcKTYWFwoFM58xdmWOiQFG1GBIvEbdmKaKiqEtiJPlBMpjtll2R/WlF9IqTOfI5gpyulSYrN618nuub+8sqzCr2qo7V2qvXrx5cw1hzYC20NmltxzrddQXrhvP88mrWk9anrf8t3yq/JP/9hpgNbQUaBXkFQz/4/VBfKFMoKuzb6LJx/4+YH/k/dm+y3bRn0/ciTtH1Yqvi0uKvm9mbr/9k/VPZT5Nbkrd0b7Xfum8bbptg273t7ttrSuRLckuGdgTvaN5J31m08/2uZbuulS4o3b+btFuye6AsqKx1j96ebXu+lvPK71Z4VjRWqlduqvy4l7P31j6PfQ37NfYX7//yM//n/gN+B5qrDKpKD+IOZh98dij6UOcvjr/UVqtVF1d/Oyw4PFATXnOp1qG2tk69bms9XC+pHz2ScKTnqPfR1gbzhgONyo3Fx8AxybEXxxOP3zsReKLjpOPJhlP6pyqbaE1FzVDzyuaxFl7LQGtca+/pgNMdbS5tTb9a/Hr4jPaZirNKZ7eeI50rODd5Pvf8eLuw/dWFlAtDHcs6Hl6MvXjn0qJL3ZcDL1+94nvlYiej8/xV16tnrjlfO33d8XrLDfsbzV12XU2/2f3W1G3f3XzT4WZrj1NPW+/C3nO33G9duO19+8od5p0bd0Pu9t6Lutffl9A30M/pH7mffv/Ng+wHEw/zHmEfFT2We1z6RP1J1e/GvzcO2A+cHfQe7Hoa8fThEHvo5R/iP74OFzyjPit9rvW8dsRm5Myo72jPi8Uvhl8KX068KvxT/s/K10avT/3l8VfXWOzY8BvRm8m3m9+pvjv8fsH7jvGw8ScfMj5MfCz6pPqp5rPj584vMV+eT6z4iv9a9s34W9v3wO+PJjMmJ4UsEWtaCiCow8nJALw9DAA1DgBaDwCkxTNaetqgGf0/TeC/8YzenjZ7AA55ABCJ6vkQdN2HukEeqklQD5uKewDY1lbq/zZxsq3NTC1yCypNSicn36GaBW8MwLe+ycmJlsnJb9Vosw8AaP8wo+GnTGcMlfreU9SdM5H3n1r6X/dYEDmGJmdAAAAACXBIWXMAAAsTAAALEwEAmpwYAAAGL2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIGV4aWY6UGl4ZWxYRGltZW5zaW9uPSIyNSIgZXhpZjpQaXhlbFlEaW1lbnNpb249IjI3IiB4bXA6Q3JlYXRlRGF0ZT0iMjAxOS0wOS0yNVQxMjoyODo1MS0wNDowMCIgeG1wOk1vZGlmeURhdGU9IjIwMTktMDktMjVUMTI6MzI6MjAtMDQ6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMTktMDktMjVUMTI6MzI6MjAtMDQ6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIzIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0iRGlzcGxheSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowZTIyOTVhMC0yYWY0LTQ2Y2UtOThlNy0zZTU2YTM0YjFkZjUiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDozYmMzNWI0YS0wNjkxLTRmNDEtODk5OC1lYWFmOTI2NGQ2NmMiIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpjZWE4Y2FhMC0yMGU1LTQzN2ItYmQ5YS03YjlmMGZiNmYyZTYiPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpjZWE4Y2FhMC0yMGU1LTQzN2ItYmQ5YS03YjlmMGZiNmYyZTYiIHN0RXZ0OndoZW49IjIwMTktMDktMjVUMTI6MzI6MjAtMDQ6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE5IChNYWNpbnRvc2gpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDowZTIyOTVhMC0yYWY0LTQ2Y2UtOThlNy0zZTU2YTM0YjFkZjUiIHN0RXZ0OndoZW49IjIwMTktMDktMjVUMTI6MzI6MjAtMDQ6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE5IChNYWNpbnRvc2gpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PuzZx/kAAAEoSURBVDjLY/z//z8DNQATA5UAhkGNe+f8f/757f+09e2kORXkNWR86P75/zCw7cax/6o9If/R1WDDOA368/cvmH7/7dP/tHXt/8k2KGlNy/8dN4/DXbf95rH/anhch9Mgz/kFYE3p6zv+f/j+GSwGokF8sgwCYZBLQC6CAZBL0V1HlEEwnLquDRxmMNfFrmyAqyEpHd1+85jh5Zd3YDYfOzeDlrgi4ehHdpFYi8f/KcdW///7DxKTQAP/e8zLJ81rfgtL/j949wws9vvvn/+9h5f9F212/090YEetqP2/+Nx2eABfeHbrv/WMNNKj/8fvX2D6+++f/+t3z/ov2Ojyn6wECQJHHlz8bzgplrws0rBn9v9XX97/L9zS/5+vwYkoQ0CYcdCVRwBmUrSjUTYI3gAAAABJRU5ErkJggg==) - no-repeat 10px center #0a7e3e; - } - } - - .spinner { - height: 42px; - align-items: center; - } - - .asm-results { - border: solid 1px #89919a; - position: absolute; - line-height: 1.5rem; - left: 2rem; - top: 4rem; - z-index: 11; - box-shadow: 0 5px 20px 0 #d9d9d9, 0 2px 8px 0 #ededed; - background-color: #fff; - border-radius: 4px; - width: 100%; - max-width: 50vw; - - @media (max-width: 1200px) { - max-width: calc(100% - 4rem); - } - - button { - margin: 0; - appearance: none; - outline: 0; - border: 0; - text-decoration: none; - cursor: pointer; - user-select: none; - vertical-align: middle; - white-space: nowrap; - background-color: transparent; - color: #51555a; - display: flex; - flex-direction: column; - cursor: pointer; - padding: 10px; - width: 100%; - align-items: flex-start; - justify-content: flex-start; - - @media (min-width: 767px) { - flex-direction: row; - } - - &:hover { - color: #32363a; - background-color: #d3d6db; - } - - span { - margin-inline-end: 15px; - margin-top: 0; - margin-bottom: 0; - margin-inline-start: 0; - word-break: break-all; - white-space: normal; - text-align: start; - - @media (min-width: 575px) { - &:last-of-type { - margin: 0; - } - } - } - } - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.spec.ts b/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.spec.ts deleted file mode 100644 index 18e2b749c47..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.spec.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { DebugElement } from '@angular/core'; -import { - waitForAsync, - ComponentFixture, - fakeAsync, - TestBed, - tick, -} from '@angular/core/testing'; -import { ReactiveFormsModule } from '@angular/forms'; -import { By } from '@angular/platform-browser'; -import { - AsmConfig, - AsmService, - CustomerSearchPage, - GlobalMessageService, - I18nTestingModule, - User, -} from '@spartacus/core'; -import { Observable, of } from 'rxjs'; -import * as testUtils from '../../../shared/utils/forms/form-test-utils'; -import { CustomerSelectionComponent } from './customer-selection.component'; -import { FormErrorsModule } from '../../../shared/index'; - -class MockGlobalMessageService { - add = jasmine.createSpy(); -} - -class MockAsmService { - customerSearch(_searchTerm: string): void {} - customerSearchReset(): void {} - getCustomerSearchResults(): Observable { - return of({}); - } - getCustomerSearchResultsLoading(): Observable { - return of(false); - } -} - -const mockCustomer: User = { - displayUid: 'Display Uid', - firstName: 'First', - lastName: 'Last', - name: 'First Last', - uid: 'customer@test.com', - customerId: '123456', -}; - -const mockCustomer2: User = { - displayUid: 'Display Uid', - firstName: 'First', - lastName: 'Last', - name: 'First Last', - uid: 'customer2@test.com', - customerId: '123456', -}; - -const mockCustomer3: User = { - displayUid: 'Display Uid', - firstName: 'First', - lastName: 'Last', - name: 'First Last', - uid: 'customer3@test.com', - customerId: '123456', -}; - -const mockCustomerSearchPage: CustomerSearchPage = { - entries: [mockCustomer, mockCustomer2, mockCustomer3], -}; - -const MockAsmConfig: AsmConfig = { - asm: { - customerSearch: { - maxResults: 20, - }, - }, -}; - -describe('CustomerSelectionComponent', () => { - let component: CustomerSelectionComponent; - let fixture: ComponentFixture; - let asmService: AsmService; - let el: DebugElement; - - const validSearchTerm = 'cUstoMer@test.com'; - - beforeEach( - waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ReactiveFormsModule, I18nTestingModule, FormErrorsModule], - declarations: [CustomerSelectionComponent], - providers: [ - { provide: AsmService, useClass: MockAsmService }, - { provide: GlobalMessageService, useClass: MockGlobalMessageService }, - { provide: AsmConfig, useValue: MockAsmConfig }, - ], - }).compileComponents(); - }) - ); - - beforeEach(() => { - fixture = TestBed.createComponent(CustomerSelectionComponent); - component = fixture.componentInstance; - component.ngOnInit(); - asmService = TestBed.inject(AsmService); - el = fixture.debugElement; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should emit selection event when submitted', () => { - spyOn(component, 'onSubmit').and.callThrough(); - spyOn(component.submitEvent, 'emit').and.stub(); - - component.customerSelectionForm.controls.searchTerm.setValue('testTerm'); - component.selectedCustomer = mockCustomer; - fixture.detectChanges(); - - testUtils.clickSubmit(fixture); - - expect(component.onSubmit).toHaveBeenCalled(); - expect(component.submitEvent.emit).toHaveBeenCalledWith({ - customerId: mockCustomer.customerId, - }); - }); - - it('should display spinner when customer search is running', () => { - spyOn(asmService, 'getCustomerSearchResultsLoading').and.returnValue( - of(true) - ); - component.ngOnInit(); - fixture.detectChanges(); - - expect(el.query(By.css('div.spinner'))).toBeTruthy(); - expect(el.query(By.css('form'))).toBeTruthy(); - }); - - it('should not display spinner when customer search is not running', () => { - fixture.detectChanges(); - - expect(el.query(By.css('div.sap-spinner'))).toBeFalsy(); - expect(el.query(By.css('form'))).toBeTruthy(); - }); - - it('should trigger search for valid search term', fakeAsync(() => { - spyOn(asmService, 'customerSearch').and.callThrough(); - component.ngOnInit(); - component.customerSelectionForm.controls.searchTerm.setValue( - validSearchTerm - ); - fixture.detectChanges(); - tick(1000); - expect(asmService.customerSearch).toHaveBeenCalledWith({ - query: validSearchTerm, - pageSize: 20, - }); - })); - - it('should display 3 search results for valid search term', () => { - spyOn(asmService, 'getCustomerSearchResults').and.returnValue( - of(mockCustomerSearchPage) - ); - component.ngOnInit(); - component.customerSelectionForm.controls.searchTerm.setValue( - validSearchTerm - ); - fixture.detectChanges(); - expect(el.queryAll(By.css('div.asm-results button')).length).toEqual( - mockCustomerSearchPage.entries.length - ); - }); - - it('should close the result list when we click out of the result list area', () => { - spyOn(asmService, 'getCustomerSearchResults').and.returnValue( - of(mockCustomerSearchPage) - ); - spyOn(asmService, 'customerSearchReset').and.stub(); - component.ngOnInit(); - component.customerSelectionForm.controls.searchTerm.setValue( - validSearchTerm - ); - fixture.detectChanges(); - expect(el.query(By.css('div.asm-results'))).toBeTruthy(); - el.nativeElement.dispatchEvent(new MouseEvent('click')); - fixture.detectChanges(); - expect(asmService.customerSearchReset).toHaveBeenCalled(); - }); - - it('should display no results message when no results are found', () => { - spyOn(asmService, 'getCustomerSearchResults').and.returnValue( - of({ entries: [] }) - ); - spyOn(asmService, 'customerSearchReset').and.stub(); - component.ngOnInit(); - component.customerSelectionForm.controls.searchTerm.setValue( - validSearchTerm - ); - fixture.detectChanges(); - expect(el.queryAll(By.css('div.asm-results button')).length).toEqual(1); - expect( - el.query(By.css('div.asm-results button')).nativeElement.innerText - ).toEqual('asm.customerSearch.noMatch'); - el.query(By.css('div.asm-results button')).nativeElement.dispatchEvent( - new MouseEvent('click') - ); - expect(asmService.customerSearchReset).toHaveBeenCalled(); - }); - - it('should be able to select a customer from the result list.', () => { - spyOn(asmService, 'getCustomerSearchResults').and.returnValue( - of(mockCustomerSearchPage) - ); - spyOn(asmService, 'customerSearchReset').and.stub(); - spyOn(component, 'selectCustomerFromList').and.callThrough(); - component.ngOnInit(); - component.customerSelectionForm.controls.searchTerm.setValue( - validSearchTerm - ); - fixture.detectChanges(); - el.query(By.css('div.asm-results button')).nativeElement.dispatchEvent( - new MouseEvent('click') - ); - fixture.detectChanges(); - expect(component.selectCustomerFromList).toHaveBeenCalled(); - expect(component.selectedCustomer).toEqual(mockCustomer); - expect(component.customerSelectionForm.controls.searchTerm.value).toEqual( - mockCustomer.name - ); - expect( - el.query(By.css('button[type="submit"]')).nativeElement.disabled - ).toBeFalsy(); - expect(asmService.customerSearchReset).toHaveBeenCalled(); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.ts b/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.ts deleted file mode 100644 index c60487dd134..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/customer-selection/customer-selection.component.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { - Component, - ElementRef, - EventEmitter, - OnDestroy, - OnInit, - Output, - ViewChild, - ViewEncapsulation, -} from '@angular/core'; -import { FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { - AsmConfig, - AsmService, - CustomerSearchPage, - User, -} from '@spartacus/core'; -import { Observable, Subscription } from 'rxjs'; -import { debounceTime } from 'rxjs/operators'; - -@Component({ - selector: 'cx-customer-selection', - templateUrl: './customer-selection.component.html', - styleUrls: ['./customer-selection.component.scss'], - encapsulation: ViewEncapsulation.None, - // eslint-disable-next-line @angular-eslint/no-host-metadata-property - host: { - '(document:click)': 'onDocumentClick($event)', - }, -}) -export class CustomerSelectionComponent implements OnInit, OnDestroy { - customerSelectionForm: FormGroup; - private subscription = new Subscription(); - searchResultsLoading$: Observable; - searchResults: Observable; - selectedCustomer: User; - - @Output() - submitEvent = new EventEmitter<{ customerId: string }>(); - - @ViewChild('resultList') resultList: ElementRef; - @ViewChild('searchTerm') searchTerm: ElementRef; - - constructor( - private fb: FormBuilder, - private asmService: AsmService, - private config: AsmConfig - ) {} - - ngOnInit(): void { - this.customerSelectionForm = this.fb.group({ - searchTerm: ['', Validators.required], - }); - this.asmService.customerSearchReset(); - this.searchResultsLoading$ = this.asmService.getCustomerSearchResultsLoading(); - this.searchResults = this.asmService.getCustomerSearchResults(); - - this.subscription.add( - this.customerSelectionForm.controls.searchTerm.valueChanges - .pipe(debounceTime(300)) - .subscribe((searchTermValue) => { - this.handleSearchTerm(searchTermValue); - }) - ); - } - - private handleSearchTerm(searchTermValue: string) { - if ( - Boolean(this.selectedCustomer) && - searchTermValue !== this.selectedCustomer.name - ) { - this.selectedCustomer = undefined; - } - if (Boolean(this.selectedCustomer)) { - return; - } - this.asmService.customerSearchReset(); - if (searchTermValue.trim().length >= 3) { - this.asmService.customerSearch({ - query: searchTermValue, - pageSize: this.config.asm.customerSearch.maxResults, - }); - } - } - - selectCustomerFromList(customer: User) { - this.selectedCustomer = customer; - this.customerSelectionForm.controls.searchTerm.setValue( - this.selectedCustomer.name - ); - this.asmService.customerSearchReset(); - } - - onSubmit(): void { - if (this.customerSelectionForm.valid && Boolean(this.selectedCustomer)) { - this.submitEvent.emit({ customerId: this.selectedCustomer.customerId }); - } else { - this.customerSelectionForm.markAllAsTouched(); - } - } - - onDocumentClick(event) { - if (Boolean(this.resultList)) { - if ( - this.resultList.nativeElement.contains(event.target) || - this.searchTerm.nativeElement.contains(event.target) - ) { - return; - } else { - this.asmService.customerSearchReset(); - } - } - } - - closeResults() { - this.asmService.customerSearchReset(); - } - - ngOnDestroy(): void { - this.subscription.unsubscribe(); - this.asmService.customerSearchReset(); - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/default-asm-layout.config.ts b/projects/storefrontlib/src/cms-components/asm/default-asm-layout.config.ts deleted file mode 100644 index 365d7cd1f91..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/default-asm-layout.config.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { LayoutConfig } from '../../layout/config/layout-config'; -import { AsmMainUiComponent } from './asm-main-ui/asm-main-ui.component'; - -export const defaultAsmLayoutConfig: LayoutConfig = { - launch: { - ASM: { - outlet: 'cx-storefront', - component: AsmMainUiComponent, - }, - }, -}; diff --git a/projects/storefrontlib/src/cms-components/asm/index.ts b/projects/storefrontlib/src/cms-components/asm/index.ts deleted file mode 100644 index e093c7437f6..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** we currently do not export all those components and services in the public API */ -export * from './asm-constants'; -export * from './asm-loader.module'; -export * from './asm-main-ui/asm-main-ui.component'; -export * from './asm-session-timer/asm-session-timer.component'; -export * from './asm-session-timer/format-timer.pipe'; -export * from './asm.module'; -export * from './csagent-login-form/csagent-login-form.component'; -export * from './customer-emulation/customer-emulation.component'; -export * from './customer-selection/customer-selection.component'; -export * from './services/index'; diff --git a/projects/storefrontlib/src/cms-components/asm/services/asm-component.service.spec.ts b/projects/storefrontlib/src/cms-components/asm/services/asm-component.service.spec.ts deleted file mode 100644 index 295f9e59aa9..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/services/asm-component.service.spec.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { AuthService, CsAgentAuthService, WindowRef } from '@spartacus/core'; -import { Observable, of } from 'rxjs'; -import { take } from 'rxjs/operators'; -import { ASM_ENABLED_LOCAL_STORAGE_KEY } from '../asm-constants'; -import { AsmComponentService } from './asm-component.service'; - -class MockAuthService implements Partial { - logout(): void {} -} - -class MockCsAgentAuthService implements Partial { - logoutCustomerSupportAgent(): Promise { - return Promise.resolve(); - } - isCustomerEmulated(): Observable { - return of(false); - } -} - -const store = {}; -const MockWindowRef = { - localStorage: { - getItem: (key: string): string => { - return key in store ? store[key] : null; - }, - setItem: (key: string, value: string) => { - store[key] = `${value}`; - }, - removeItem: (key: string): void => { - if (key in store) { - delete store[key]; - } - }, - }, -}; - -describe('AsmComponentService', () => { - let authService: AuthService; - let csAgentAuthService: CsAgentAuthService; - let windowRef: WindowRef; - let asmComponentService: AsmComponentService; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - { provide: AuthService, useClass: MockAuthService }, - { provide: CsAgentAuthService, useClass: MockCsAgentAuthService }, - { provide: WindowRef, useValue: MockWindowRef }, - ], - }); - - asmComponentService = TestBed.inject(AsmComponentService); - authService = TestBed.inject(AuthService); - csAgentAuthService = TestBed.inject(CsAgentAuthService); - windowRef = TestBed.inject(WindowRef); - }); - - it('should be created', () => { - expect(asmComponentService).toBeTruthy(); - }); - - describe('logoutCustomerSupportAgentAndCustomer()', () => { - it('should logout csagent no matter the emulation state', () => { - spyOn(csAgentAuthService, 'logoutCustomerSupportAgent').and.stub(); - - asmComponentService.logoutCustomerSupportAgentAndCustomer(); - - expect(csAgentAuthService.logoutCustomerSupportAgent).toHaveBeenCalled(); - }); - }); - - describe('logoutCustomer()', () => { - it('should logout customer and redirect to home.', () => { - spyOn(authService, 'logout').and.stub(); - asmComponentService.logoutCustomer(); - expect(authService.logout).toHaveBeenCalled(); - }); - }); - - describe('isCustomerEmulationSessionInProgress()', () => { - it('should return true when user token is from an emulation session', () => { - spyOn(csAgentAuthService, 'isCustomerEmulated').and.returnValue(of(true)); - let result = false; - asmComponentService - .isCustomerEmulationSessionInProgress() - .pipe(take(1)) - .subscribe((value) => (result = value)); - expect(result).toBe(true); - }); - - it('should return false when user token is not from an emulation session', () => { - spyOn(csAgentAuthService, 'isCustomerEmulated').and.returnValue( - of(false) - ); - let result = false; - asmComponentService - .isCustomerEmulationSessionInProgress() - .pipe(take(1)) - .subscribe((value) => (result = value)); - expect(result).toBe(false); - }); - }); - - describe('Unload', () => { - it('should remove local storage key to false on unload', () => { - windowRef.localStorage.setItem(ASM_ENABLED_LOCAL_STORAGE_KEY, 'true'); - asmComponentService.unload(); - expect( - windowRef.localStorage.getItem(ASM_ENABLED_LOCAL_STORAGE_KEY) - ).toBeNull(); - }); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/asm/services/asm-component.service.ts b/projects/storefrontlib/src/cms-components/asm/services/asm-component.service.ts deleted file mode 100644 index e5d14e593b6..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/services/asm-component.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Injectable } from '@angular/core'; -import { AuthService, CsAgentAuthService, WindowRef } from '@spartacus/core'; -import { Observable } from 'rxjs'; -import { ASM_ENABLED_LOCAL_STORAGE_KEY } from '../asm-constants'; - -@Injectable({ - providedIn: 'root', -}) -export class AsmComponentService { - constructor( - protected authService: AuthService, - protected csAgentAuthService: CsAgentAuthService, - protected winRef: WindowRef - ) {} - - logoutCustomerSupportAgentAndCustomer(): void { - this.csAgentAuthService.logoutCustomerSupportAgent(); - } - - logoutCustomer(): void { - this.authService.logout(); - } - - isCustomerEmulationSessionInProgress(): Observable { - return this.csAgentAuthService.isCustomerEmulated(); - } - - /** - * We're currently only removing the persisted storage in the browser - * to ensure the ASM experience isn't loaded on the next visit. There are a few - * optimizations we could think of: - * - drop the `asm` parameter from the URL, in case it's still there - * - remove the generated UI from the DOM (outlets currently do not support this) - */ - unload() { - if (this.winRef.localStorage) { - this.winRef.localStorage.removeItem(ASM_ENABLED_LOCAL_STORAGE_KEY); - } - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/services/asm-enabler.service.spec.ts b/projects/storefrontlib/src/cms-components/asm/services/asm-enabler.service.spec.ts deleted file mode 100644 index 0e52c6c5de3..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/services/asm-enabler.service.spec.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { Location } from '@angular/common'; -import { ComponentFactoryResolver } from '@angular/core'; -import { TestBed } from '@angular/core/testing'; -import { WindowRef } from '@spartacus/core'; -import { LayoutConfig } from '../../../layout/config/layout-config'; -import { OutletService } from '../../../cms-structure/outlet/index'; -import { LaunchDialogService } from '../../../layout/launch-dialog/index'; -import { ASM_ENABLED_LOCAL_STORAGE_KEY } from '../asm-constants'; -import { AsmEnablerService } from './asm-enabler.service'; - -const store = {}; -const MockWindowRef = { - localStorage: { - getItem: (key: string): string => { - return key in store ? store[key] : null; - }, - setItem: (key: string, value: string) => { - store[key] = `${value}`; - }, - removeItem: (key: string): void => { - if (key in store) { - delete store[key]; - } - }, - }, -}; - -class MockComponentFactoryResolver { - resolveComponentFactory() {} -} - -class MockOutletService { - add() {} -} - -class MockLocation { - path() { - return ''; - } -} - -class MockLaunchDialogService { - launch() {} -} - -const mockLaunchConfig: LayoutConfig = { - launch: { - ASM: { - outlet: 'cx-outlet-test', - component: {}, - }, - }, -}; - -describe('AsmEnablerService', () => { - let asmEnablerService: AsmEnablerService; - let windowRef: WindowRef; - let location: Location; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [ - { provide: WindowRef, useValue: MockWindowRef }, - { - provide: ComponentFactoryResolver, - useClass: MockComponentFactoryResolver, - }, - { provide: OutletService, useClass: MockOutletService }, - { provide: Location, useClass: MockLocation }, - { provide: LayoutConfig, useValue: mockLaunchConfig }, - { - provide: LaunchDialogService, - useClass: MockLaunchDialogService, - }, - ], - }); - - asmEnablerService = TestBed.inject(AsmEnablerService); - windowRef = TestBed.inject(WindowRef); - location = TestBed.inject(Location); - - windowRef.localStorage.removeItem(ASM_ENABLED_LOCAL_STORAGE_KEY); - }); - - it('should be created', () => { - expect(asmEnablerService).toBeTruthy(); - }); - - describe('Open ASM based on URL parameter', () => { - it('should add UI when ?asm=true', () => { - spyOn(location, 'path').and.returnValue('/any/url?asm=true'); - spyOn(asmEnablerService, 'addUi').and.stub(); - asmEnablerService.load(); - expect((asmEnablerService).addUi).toHaveBeenCalled(); - }); - - it('should not add UI when asm param is not used', () => { - spyOn(location, 'path').and.returnValue('/any/url'); - spyOn(asmEnablerService, 'addUi').and.stub(); - asmEnablerService.load(); - expect((asmEnablerService).addUi).not.toHaveBeenCalled(); - }); - }); - - describe('Open ASM based on previous usage', () => { - it('should add UI when localStorage key asm_enabled is true', () => { - windowRef.localStorage.setItem(ASM_ENABLED_LOCAL_STORAGE_KEY, 'true'); - spyOn(location, 'path').and.returnValue('/any/url'); - spyOn(asmEnablerService, 'addUi').and.stub(); - asmEnablerService.load(); - expect((asmEnablerService).addUi).toHaveBeenCalled(); - }); - - it('should not add UI when localStorage asm_enabled is false ', () => { - windowRef.localStorage.setItem(ASM_ENABLED_LOCAL_STORAGE_KEY, 'false'); - spyOn(location, 'path').and.returnValue('/any/url'); - spyOn(asmEnablerService, 'addUi').and.stub(); - asmEnablerService.load(); - expect((asmEnablerService).addUi).not.toHaveBeenCalled(); - }); - - it('should not add UI when localStorage asm_enabled is not available ', () => { - windowRef.localStorage.removeItem(ASM_ENABLED_LOCAL_STORAGE_KEY); - spyOn(location, 'path').and.returnValue('/any/url'); - spyOn(asmEnablerService, 'addUi').and.stub(); - asmEnablerService.load(); - expect((asmEnablerService).addUi).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/asm/services/asm-enabler.service.ts b/projects/storefrontlib/src/cms-components/asm/services/asm-enabler.service.ts deleted file mode 100644 index 7727eaf42d8..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/services/asm-enabler.service.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { Location } from '@angular/common'; -import { Injectable } from '@angular/core'; -import { WindowRef } from '@spartacus/core'; -import { LAUNCH_CALLER } from '../../../layout/launch-dialog/config/index'; -import { LaunchDialogService } from '../../../layout/launch-dialog/services/launch-dialog.service'; -import { ASM_ENABLED_LOCAL_STORAGE_KEY } from '../asm-constants'; - -/** - * The AsmEnablerService is used to enable ASM for those scenario's - * where it's actually used. This service is added to avoid any polution - * of the UI and runtime performance for the ordinary production user. - */ -@Injectable({ - providedIn: 'root', -}) -export class AsmEnablerService { - constructor( - protected location: Location, - protected winRef: WindowRef, - protected launchDialogService: LaunchDialogService - ) {} - - /** - * Loads the ASM UI if needed. The ASM UI will be added based on the - * existence of a URL parameter or previous usage given by local storage. - */ - load(): void { - if (this.isEnabled()) { - this.addUi(); - } - } - - /** - * Indicates whether the ASM module is enabled. - */ - isEnabled(): boolean { - if (this.isLaunched() && !this.isUsedBefore()) { - if (this.winRef.localStorage) { - this.winRef.localStorage.setItem(ASM_ENABLED_LOCAL_STORAGE_KEY, 'true'); - } - } - return this.isLaunched() || this.isUsedBefore(); - } - - /** - * Indicates whether ASM is launched through the URL, - * using the asm flag in the URL. - */ - protected isLaunched(): boolean { - const params = this.location.path().split('?')[1]; - return params && params.split('&').includes('asm=true'); - } - - /** - * Evaluates local storage where we persist the usage of ASM. - */ - protected isUsedBefore(): boolean { - return ( - this.winRef.localStorage && - this.winRef.localStorage.getItem(ASM_ENABLED_LOCAL_STORAGE_KEY) === 'true' - ); - } - - /** - * Adds the ASM UI by using the `cx-storefront` outlet. - */ - protected addUi(): void { - this.launchDialogService.launch(LAUNCH_CALLER.ASM); - } -} diff --git a/projects/storefrontlib/src/cms-components/asm/services/index.ts b/projects/storefrontlib/src/cms-components/asm/services/index.ts deleted file mode 100644 index aec5d011e1f..00000000000 --- a/projects/storefrontlib/src/cms-components/asm/services/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './asm-component.service'; -export * from './asm-enabler.service'; diff --git a/projects/storefrontlib/src/cms-components/cms-lib.module.ts b/projects/storefrontlib/src/cms-components/cms-lib.module.ts index 2bfaa5d2637..af066c7d378 100644 --- a/projects/storefrontlib/src/cms-components/cms-lib.module.ts +++ b/projects/storefrontlib/src/cms-components/cms-lib.module.ts @@ -1,7 +1,6 @@ import { NgModule } from '@angular/core'; import { HamburgerMenuModule } from '../layout/index'; import { AnonymousConsentManagementBannerModule } from './anonymous-consent-management/anonymous-consent-management.module'; -import { AsmModule } from './asm/asm.module'; import { CartComponentModule } from './cart/cart.module'; import { CheckoutComponentModule } from './checkout/checkout.module'; import { BannerCarouselModule } from './content/banner-carousel/banner-carousel.module'; @@ -65,7 +64,6 @@ import { WishListModule } from './wish-list/wish-list.module'; @NgModule({ imports: [ AnonymousConsentManagementBannerModule, - AsmModule, HamburgerMenuModule, CmsParagraphModule, LinkModule, diff --git a/projects/storefrontlib/src/cms-components/index.ts b/projects/storefrontlib/src/cms-components/index.ts index 37771107699..de4d8c06840 100644 --- a/projects/storefrontlib/src/cms-components/index.ts +++ b/projects/storefrontlib/src/cms-components/index.ts @@ -1,5 +1,4 @@ export * from './anonymous-consent-management/index'; -export * from './asm/asm.module'; export * from './cart/index'; export * from './checkout/index'; export * from './cms-lib.module'; diff --git a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/index.ts b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/index.ts index 24b487811b3..20021c88d25 100644 --- a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/index.ts +++ b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/index.ts @@ -1,5 +1,4 @@ export * from './default-replenishment-order-cancellation-layout.config'; -export * from './replenishment-order-cancellation/replenishment-order-cancellation-launch-dialog.service'; export * from './replenishment-order-cancellation/replenishment-order-cancellation.component'; export * from './replenishment-order-details.module'; export * from './replenishment-order-details.service'; diff --git a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation-launch-dialog.service.spec.ts b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation-launch-dialog.service.spec.ts deleted file mode 100644 index 5cfd4f96cd1..00000000000 --- a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation-launch-dialog.service.spec.ts +++ /dev/null @@ -1,90 +0,0 @@ -// TODO(#12167): remove the file -import { Component, ComponentRef, ViewContainerRef } from '@angular/core'; -import { TestBed } from '@angular/core/testing'; -import { of } from 'rxjs'; -import { - LaunchDialogService, - LAUNCH_CALLER, -} from '../../../../../layout/launch-dialog/index'; -import { ReplenishmentOrderCancellationLaunchDialogService } from './replenishment-order-cancellation-launch-dialog.service'; - -@Component({ - template: '', -}) -class TestContainerComponent { - constructor(public vcr: ViewContainerRef) {} -} - -class MockLaunchDialogService { - launch() {} - clear() {} - get dialogClose() { - return of('close'); - } -} - -describe('ReplenishmentOrderCancellationLaunchDialogService', () => { - let service: ReplenishmentOrderCancellationLaunchDialogService; - let launchDialogService: LaunchDialogService; - let component: TestContainerComponent; - let componentRef: ComponentRef; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [TestContainerComponent], - providers: [ - { provide: LaunchDialogService, useClass: MockLaunchDialogService }, - ], - }).compileComponents(); - - service = TestBed.inject(ReplenishmentOrderCancellationLaunchDialogService); - launchDialogService = TestBed.inject(LaunchDialogService); - component = TestBed.createComponent(TestContainerComponent) - .componentInstance; - componentRef = TestBed.createComponent(TestContainerComponent).componentRef; - }); - - it('should create', () => { - expect(service).toBeTruthy(); - }); - - describe('openDialog', () => { - beforeEach(() => { - spyOn(launchDialogService, 'launch').and.returnValue(of(componentRef)); - }); - - it('should call LaunchDialogService launch', () => { - service.openDialog(null, component.vcr, { test: 123 }); - - expect(launchDialogService.launch).toHaveBeenCalledWith( - LAUNCH_CALLER.REPLENISHMENT_ORDER, - component.vcr, - { - test: 123, - } - ); - }); - - it('should call LaunchDialogService clear on close', () => { - spyOn(launchDialogService, 'clear'); - - const comp = service.openDialog(null, component.vcr); - - comp.subscribe(); - - expect(launchDialogService.clear).toHaveBeenCalledWith( - LAUNCH_CALLER.REPLENISHMENT_ORDER - ); - }); - - it('should destroy component on close', () => { - spyOn(componentRef, 'destroy'); - - const comp = service.openDialog(null, component.vcr); - - comp.subscribe(); - - expect(componentRef.destroy).toHaveBeenCalled(); - }); - }); -}); diff --git a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation-launch-dialog.service.ts b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation-launch-dialog.service.ts deleted file mode 100644 index 1d2f6a16ba0..00000000000 --- a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation-launch-dialog.service.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ElementRef, Injectable, ViewContainerRef } from '@angular/core'; -import { combineLatest, Observable } from 'rxjs'; -import { filter, map, tap } from 'rxjs/operators'; -import { - LaunchDialogService, - LAUNCH_CALLER, -} from '../../../../../layout/launch-dialog/index'; - -// TODO(#12167): deprecations cleanup -/** - * @deprecated since 3.3 - use `LaunchDialogService` instead - */ -@Injectable({ providedIn: 'root' }) -export class ReplenishmentOrderCancellationLaunchDialogService { - constructor(protected launchDialogService: LaunchDialogService) {} - - /** - * @deprecated since 3.3 - use `LaunchDialogService.openDialog` with LAUNCH_CALLER.REPLENISHMENT_ORDER instead - */ - openDialog( - openElement?: ElementRef, - vcr?: ViewContainerRef, - data?: any - ): Observable | undefined { - const component = this.launchDialogService.launch( - LAUNCH_CALLER.REPLENISHMENT_ORDER, - vcr, - data - ); - - if (component) { - return combineLatest([ - component, - this.launchDialogService.dialogClose, - ]).pipe( - filter(([, close]) => close && close !== undefined), - tap(([comp]) => { - openElement?.nativeElement.focus(); - this.launchDialogService.clear(LAUNCH_CALLER.REPLENISHMENT_ORDER); - comp.destroy(); - }), - map(([comp]) => comp) - ); - } - } -} diff --git a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.spec.ts b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.spec.ts index 4b3190fb188..df1137fafac 100644 --- a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.spec.ts +++ b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.spec.ts @@ -15,7 +15,6 @@ import { } from '@spartacus/core'; import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { ReplenishmentOrderCancellationLaunchDialogService } from './replenishment-order-cancellation-launch-dialog.service'; import { ReplenishmentOrderCancellationComponent } from './replenishment-order-cancellation.component'; const mockReplenishmentOrder: ReplenishmentOrder = { @@ -36,9 +35,6 @@ class MockUserReplenishmentOrderService { clearReplenishmentOrderDetails() {} } -class MockReplenishmentOrderCancellationLaunchDialogService { - openDialog(_openElement?: ElementRef, _vcr?: ViewContainerRef) {} -} @Pipe({ name: 'cxUrl', }) @@ -73,11 +69,6 @@ describe('ReplenishmentOrderCancellationComponent', () => { provide: UserReplenishmentOrderService, useClass: MockUserReplenishmentOrderService, }, - // TODO(#12167): remove unused class and provider - { - provide: ReplenishmentOrderCancellationLaunchDialogService, - useClass: MockReplenishmentOrderCancellationLaunchDialogService, - }, { provide: LaunchDialogService, useClass: MockLaunchDialogService, diff --git a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.ts b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.ts index 65d56dbe9b3..18f0070f6bd 100644 --- a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.ts +++ b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation.component.ts @@ -9,13 +9,10 @@ import { ReplenishmentOrder, UserReplenishmentOrderService, } from '@spartacus/core'; -import { - LaunchDialogService, - LAUNCH_CALLER, -} from '../../../../../layout/launch-dialog'; +import { LaunchDialogService } from '../../../../../layout/launch-dialog/services/launch-dialog.service'; +import { LAUNCH_CALLER } from '../../../../../layout/launch-dialog/config/launch-config'; import { Observable, Subscription } from 'rxjs'; import { take } from 'rxjs/operators'; -import { ReplenishmentOrderCancellationLaunchDialogService } from './replenishment-order-cancellation-launch-dialog.service'; @Component({ selector: 'cx-replenishment-order-cancellation', @@ -28,58 +25,21 @@ export class ReplenishmentOrderCancellationComponent implements OnDestroy { replenishmentOrder$: Observable = this.userReplenishmentOrderService.getReplenishmentOrderDetails(); - // TODO(#12167): make launchDialogService a required dependency instead of replenishmentOrderCancellationLaunchDialogService and remove deprecated constructors - /** - * @deprecated since 3.3 - */ - constructor( - userReplenishmentOrderService: UserReplenishmentOrderService, - replenishmentOrderCancellationLaunchDialogService: ReplenishmentOrderCancellationLaunchDialogService, - vcr: ViewContainerRef - ); - /** - * Default constructor will be - * - * @param {UserReplenishmentOrderService} userReplenishmentOrderService - * @param {ViewContainerRef} vcr - * @param {LaunchDialogService} launchDialogService - */ - constructor( - userReplenishmentOrderService: UserReplenishmentOrderService, - replenishmentOrderCancellationLaunchDialogService: ReplenishmentOrderCancellationLaunchDialogService, - vcr: ViewContainerRef, - // eslint-disable-next-line @typescript-eslint/unified-signatures - launchDialogService: LaunchDialogService - ); - constructor( protected userReplenishmentOrderService: UserReplenishmentOrderService, - protected replenishmentOrderCancellationLaunchDialogService: ReplenishmentOrderCancellationLaunchDialogService, protected vcr: ViewContainerRef, - protected launchDialogService?: LaunchDialogService + protected launchDialogService: LaunchDialogService ) {} openDialog() { - // TODO(#12167): use launchDialogService only - if (this.launchDialogService) { - const dialog = this.launchDialogService.openDialog( - LAUNCH_CALLER.REPLENISHMENT_ORDER, - this.element, - this.vcr - ); - - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } - } else { - const dialog = this.replenishmentOrderCancellationLaunchDialogService.openDialog( - this.element, - this.vcr - ); - - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } + const dialog = this.launchDialogService.openDialog( + LAUNCH_CALLER.REPLENISHMENT_ORDER, + this.element, + this.vcr + ); + + if (dialog) { + this.subscription.add(dialog.pipe(take(1)).subscribe()); } } diff --git a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.spec.ts b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.spec.ts index fea7ba2e28a..35983b6c106 100644 --- a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.spec.ts +++ b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.spec.ts @@ -20,7 +20,6 @@ import { } from '@spartacus/core'; import { LaunchDialogService, LAUNCH_CALLER } from '@spartacus/storefront'; import { BehaviorSubject, Observable, of } from 'rxjs'; -import { ReplenishmentOrderCancellationLaunchDialogService } from '../replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation-launch-dialog.service'; import { ReplenishmentOrderHistoryComponent } from './replenishment-order-history.component'; const mockReplenishmentOrders: ReplenishmentOrderList = { @@ -78,10 +77,6 @@ class MockSortingComponent { @Output() sortListEvent = new EventEmitter(); } -class MockReplenishmentOrderCancellationLaunchDialogService { - openDialog(_openElement?: ElementRef, _vcr?: ViewContainerRef) {} -} - @Pipe({ name: 'cxUrl', }) @@ -143,11 +138,6 @@ describe('ReplenishmentOrderHistoryComponent', () => { provide: UserReplenishmentOrderService, useClass: MockUserReplenishmentOrderService, }, - // TODO(#12167): remove unused class and provider - { - provide: ReplenishmentOrderCancellationLaunchDialogService, - useClass: MockReplenishmentOrderCancellationLaunchDialogService, - }, { provide: LaunchDialogService, useClass: MockLaunchDialogService, diff --git a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.ts b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.ts index 4477d120308..e91b36311c3 100644 --- a/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.ts +++ b/projects/storefrontlib/src/cms-components/myaccount/order/replenishment-order-history/replenishment-order-history.component.ts @@ -13,13 +13,10 @@ import { TranslationService, UserReplenishmentOrderService, } from '@spartacus/core'; -import { ReplenishmentOrderCancellationLaunchDialogService } from '../replenishment-order-details/replenishment-order-cancellation/replenishment-order-cancellation-launch-dialog.service'; import { combineLatest, Observable, Subscription } from 'rxjs'; import { map, take, tap } from 'rxjs/operators'; -import { - LAUNCH_CALLER, - LaunchDialogService, -} from '../../../../layout/launch-dialog'; +import { LaunchDialogService } from '../../../../layout/launch-dialog/services/launch-dialog.service'; +import { LAUNCH_CALLER } from '../../../../layout/launch-dialog/config/launch-config'; @Component({ selector: 'cx-replenishment-order-history', @@ -45,44 +42,13 @@ export class ReplenishmentOrderHistoryComponent implements OnDestroy { ); isLoaded$: Observable = this.userReplenishmentOrderService.getReplenishmentOrderHistoryListSuccess(); - // TODO(#12167): make launchDialogService a required dependency instead of replenishmentOrderCancellationLaunchDialogService and remove deprecated constructors - /** - * @deprecated since 3.3 - */ - constructor( - routing: RoutingService, - userReplenishmentOrderService: UserReplenishmentOrderService, - replenishmentOrderCancellationLaunchDialogService: ReplenishmentOrderCancellationLaunchDialogService, - translation: TranslationService, - vcr: ViewContainerRef - ); - - /** - * Default constructor will be - * - * @param {RoutingService} routing - * @param {UserReplenishmentOrderService} userReplenishmentOrderService - * @param {TranslationService} translation - * @param {ViewContainerRef} vcr - * @param {LaunchDialogService} launchDialogService - */ - constructor( - routing: RoutingService, - userReplenishmentOrderService: UserReplenishmentOrderService, - replenishmentOrderCancellationLaunchDialogService: ReplenishmentOrderCancellationLaunchDialogService, - translation: TranslationService, - vcr: ViewContainerRef, - // eslint-disable-next-line @typescript-eslint/unified-signatures - launchDialogService: LaunchDialogService - ); constructor( protected routing: RoutingService, protected userReplenishmentOrderService: UserReplenishmentOrderService, - protected replenishmentOrderCancellationLaunchDialogService: ReplenishmentOrderCancellationLaunchDialogService, protected translation: TranslationService, protected vcr: ViewContainerRef, - protected launchDialogService?: LaunchDialogService + protected launchDialogService: LaunchDialogService ) {} changeSortCode(sortCode: string): void { @@ -130,28 +96,15 @@ export class ReplenishmentOrderHistoryComponent implements OnDestroy { } openDialog(event: Event, replenishmentOrderCode: string): void { - // TODO(#12167): use launchDialogService only - if (this.launchDialogService) { - const dialog = this.launchDialogService.openDialog( - LAUNCH_CALLER.REPLENISHMENT_ORDER, - this.element, - this.vcr, - replenishmentOrderCode - ); - - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } - } else { - const dialog = this.replenishmentOrderCancellationLaunchDialogService.openDialog( - this.element, - this.vcr, - replenishmentOrderCode - ); + const dialog = this.launchDialogService.openDialog( + LAUNCH_CALLER.REPLENISHMENT_ORDER, + this.element, + this.vcr, + replenishmentOrderCode + ); - if (dialog) { - this.subscription.add(dialog.pipe(take(1)).subscribe()); - } + if (dialog) { + this.subscription.add(dialog.pipe(take(1)).subscribe()); } event.stopPropagation(); } diff --git a/projects/storefrontlib/src/layout/main/storefront.component.spec.ts b/projects/storefrontlib/src/layout/main/storefront.component.spec.ts index 753a163ba75..c3b95e5c60d 100644 --- a/projects/storefrontlib/src/layout/main/storefront.component.spec.ts +++ b/projects/storefrontlib/src/layout/main/storefront.component.spec.ts @@ -8,11 +8,6 @@ import { MockFeatureDirective } from '../../shared/test/mock-feature-directive'; import { HamburgerMenuService } from '../header/hamburger-menu/hamburger-menu.service'; import { StorefrontComponent } from './storefront.component'; -@Component({ - selector: 'cx-asm', - template: '', -}) -class MockAsmRootComponent {} @Component({ selector: 'cx-header', template: '', @@ -83,7 +78,6 @@ describe('StorefrontComponent', () => { MockFooterComponent, DynamicSlotComponent, MockPageLayoutComponent, - MockAsmRootComponent, MockFeatureDirective, MockSchemaComponent, MockOutletDirective, diff --git a/projects/storefrontlib/src/recipes/storefront.module.ts b/projects/storefrontlib/src/recipes/storefront.module.ts index 73988c65372..b51b5a8d8fe 100644 --- a/projects/storefrontlib/src/recipes/storefront.module.ts +++ b/projects/storefrontlib/src/recipes/storefront.module.ts @@ -5,12 +5,10 @@ import { StoreModule } from '@ngrx/store'; import { ExternalRoutesModule, OccModule, - PersonalizationModule, provideConfig, SiteContextModule, SmartEditModule, } from '@spartacus/core'; -import { AsmModule } from '../cms-components/asm/asm.module'; import { ProductDetailsPageModule } from '../cms-pages/product-details-page/product-details-page.module'; import { ProductListingPageModule } from '../cms-pages/product-listing-page/product-listing-page.module'; import { MainModule } from '../layout/main/main.module'; @@ -31,14 +29,11 @@ import { StorefrontFoundationModule } from './storefront-foundation.module'; StoreModule.forRoot({}), EffectsModule.forRoot([]), - AsmModule, - StorefrontFoundationModule, MainModule, SiteContextModule.forRoot(), // should be imported after RouterModule.forRoot, because it overwrites UrlSerializer SmartEditModule.forRoot(), // should be custom - PersonalizationModule.forRoot(), // should be custom // opt-in explicitly OccModule.forRoot(), diff --git a/projects/storefrontlib/src/shared/components/modal/modal.service.ts b/projects/storefrontlib/src/shared/components/modal/modal.service.ts index cdc45c01339..7c3e737f723 100644 --- a/projects/storefrontlib/src/shared/components/modal/modal.service.ts +++ b/projects/storefrontlib/src/shared/components/modal/modal.service.ts @@ -31,8 +31,9 @@ export class ModalService { protected featureConfigService?: FeatureConfigService ) {} - protected readonly rootComponent = this.applicationRef?.components?.[0] - .location?.nativeElement; + protected get rootComponent() { + return this.applicationRef?.components?.[0]?.location?.nativeElement; + } open(content: any, options?: ModalOptions): ModalRef { let activeModal: ModalRef; diff --git a/projects/storefrontlib/src/storefront-config.ts b/projects/storefrontlib/src/storefront-config.ts index d2e799346ee..be4ca750d2b 100644 --- a/projects/storefrontlib/src/storefront-config.ts +++ b/projects/storefrontlib/src/storefront-config.ts @@ -1,6 +1,5 @@ import { AnonymousConsentsConfig, - AsmConfig, AuthConfig, CartConfig, CmsConfig, @@ -9,7 +8,6 @@ import { I18nConfig, OccConfig, PageMetaConfig, - PersonalizationConfig, RoutingConfig, SiteContextConfig, StateConfig, @@ -42,14 +40,12 @@ export type StorefrontConfig = | MediaConfig | RoutingConfig | I18nConfig - | PersonalizationConfig | IconConfig | CheckoutConfig | GlobalMessageConfig | ExternalRoutesConfig | ViewConfig | FeatureToggles - | AsmConfig | SkipLinkConfig | PaginationConfig | CartConfig diff --git a/projects/storefrontstyles/scss/_components.scss b/projects/storefrontstyles/scss/_components.scss index 93abafbd148..66c97ae515c 100644 --- a/projects/storefrontstyles/scss/_components.scss +++ b/projects/storefrontstyles/scss/_components.scss @@ -13,7 +13,6 @@ $cart-components-whitelist: () !default; $checkout-components-whitelist: () !default; $content-components-whitelist: () !default; $misc-components-whitelist: () !default; -$asm-components-whitelist: () !default; $pwa-components-whitelist: () !default; $cds-components-whitelist: () !default; $wish-list-components-whitelist: () !default; @@ -31,7 +30,6 @@ $selectors: mergeAll( $myaccount-components-whitelist, $pwa-components-whitelist, $cds-components-whitelist, - $asm-components-whitelist, $wish-list-components-whitelist ) ); diff --git a/scripts/install/run.sh b/scripts/install/run.sh index e54ae90a76c..a69bb8f9afc 100755 --- a/scripts/install/run.sh +++ b/scripts/install/run.sh @@ -117,22 +117,13 @@ function add_product_configurator { # Don't install b2b features here (use add_b2b function for that) function add_feature_libs { - ng add @spartacus/storefinder@${SPARTACUS_VERSION} --interactive false - ng add @spartacus/smartedit@${SPARTACUS_VERSION} --interactive false - ng add @spartacus/asm@${SPARTACUS_VERSION} --interactive false - ng add @spartacus/tracking@${SPARTACUS_VERSION} --interactive false --features="Personalization" --features="TMS-GTM" --features="TMS-AEPL" - ng add @spartacus/product@${SPARTACUS_VERSION} --interactive false + ng add @spartacus/tracking@${SPARTACUS_VERSION} --interactive false --features="TMS-GTM" --features="TMS-AEPL" ng add @spartacus/qualtrics@${SPARTACUS_VERSION} --interactive false - ng add @spartacus/cart@${SPARTACUS_VERSION} --interactive false } function add_spartacus_csr { ( cd ${INSTALLATION_DIR}/${1} - if [ "${ADD_B2B_LIBS}" = true ] ; then - ng add @spartacus/schematics@${SPARTACUS_VERSION} --overwriteAppComponent true --baseUrl ${BACKEND_URL} --occPrefix ${OCC_PREFIX} --configuration b2b --interactive false - else - ng add @spartacus/schematics@${SPARTACUS_VERSION} --overwriteAppComponent true --baseUrl ${BACKEND_URL} --occPrefix ${OCC_PREFIX} --configuration b2c --interactive false - fi + ng add @spartacus/schematics@${SPARTACUS_VERSION} --overwriteAppComponent true --baseUrl ${BACKEND_URL} --occPrefix ${OCC_PREFIX} --interactive false add_feature_libs add_b2b add_cdc @@ -142,11 +133,7 @@ function add_spartacus_csr { function add_spartacus_ssr { ( cd ${INSTALLATION_DIR}/${1} - if [ "${ADD_B2B_LIBS}" = true ] ; then - ng add @spartacus/schematics@${SPARTACUS_VERSION} --overwriteAppComponent true --baseUrl ${BACKEND_URL} --occPrefix ${OCC_PREFIX} --ssr --configuration b2b --interactive false - else - ng add @spartacus/schematics@${SPARTACUS_VERSION} --overwriteAppComponent true --baseUrl ${BACKEND_URL} --occPrefix ${OCC_PREFIX} --ssr --configuration b2c --interactive false - fi + ng add @spartacus/schematics@${SPARTACUS_VERSION} --overwriteAppComponent true --baseUrl ${BACKEND_URL} --occPrefix ${OCC_PREFIX} --ssr --interactive false add_feature_libs add_b2b add_cdc @@ -156,11 +143,7 @@ function add_spartacus_ssr { function add_spartacus_ssr_pwa { ( cd ${INSTALLATION_DIR}/${1} - if [ "${ADD_B2B_LIBS}" = true ] ; then - ng add @spartacus/schematics@${SPARTACUS_VERSION} --overwriteAppComponent true --baseUrl ${BACKEND_URL} --occPrefix ${OCC_PREFIX} --ssr --pwa --configuration b2b --interactive false - else - ng add @spartacus/schematics@${SPARTACUS_VERSION} --overwriteAppComponent true --baseUrl ${BACKEND_URL} --occPrefix ${OCC_PREFIX} --ssr --pwa --configuration b2c --interactive false - fi + ng add @spartacus/schematics@${SPARTACUS_VERSION} --overwriteAppComponent true --baseUrl ${BACKEND_URL} --occPrefix ${OCC_PREFIX} --ssr --pwa --interactive false add_feature_libs add_b2b add_cdc