Skip to content

Commit

Permalink
fix: fix failing delivery mode after clearing the cart and creating a…
Browse files Browse the repository at this point in the history
… new one by clearing checkout data when deleting a cart(#17613)

Issue was fixed by triggering the CheckoutQueryResetEvent on DeleteCartEvent.

DEPRECATED:

Constructor in CheckoutDeliveryModeComponent is marked as deprecated. GlobalMessageService will be required from v.7.0

Closes #3866
  • Loading branch information
rmch91 authored Jul 11, 2023
1 parent 801982b commit 16fee09
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ <h2 class="cx-checkout-title d-none d-lg-block d-xl-block">
<div class="col-md-12 col-lg-6">
<button
class="btn btn-block btn-primary"
[disabled]="deliveryModeInvalid"
[disabled]="deliveryModeInvalid || (isSetDeliveryModeHttpError$ | async)"
(click)="next()"
>
{{ 'common.continue' | cxTranslate }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,14 @@ import {
OrderEntry,
} from '@spartacus/cart/base/root';
import { CheckoutDeliveryModesFacade } from '@spartacus/checkout/base/root';
import { I18nTestingModule, QueryState } from '@spartacus/core';
import {
GlobalMessageService,
GlobalMessageType,
I18nTestingModule,
QueryState,
} from '@spartacus/core';
import { OutletModule } from '@spartacus/storefront';
import { BehaviorSubject, EMPTY, of } from 'rxjs';
import { BehaviorSubject, EMPTY, of, throwError } from 'rxjs';
import { CheckoutConfigService } from '../services/checkout-config.service';
import { CheckoutStepService } from '../services/checkout-step.service';
import { CheckoutDeliveryModeComponent } from './checkout-delivery-mode.component';
Expand Down Expand Up @@ -88,11 +93,17 @@ class MockCartService implements Partial<ActiveCartFacade> {
getPickupEntries = createSpy().and.returnValue(of([]));
}

class MockGlobalMessageService implements Partial<GlobalMessageService> {
add() {}
}

describe('CheckoutDeliveryModeComponent', () => {
let component: CheckoutDeliveryModeComponent;
let fixture: ComponentFixture<CheckoutDeliveryModeComponent>;
let checkoutConfigService: CheckoutConfigService;
let checkoutStepService: CheckoutStepService;
let checkoutDeliveryModesFacade: CheckoutDeliveryModesFacade;
let globalMessageService: GlobalMessageService;

beforeEach(
waitForAsync(() => {
Expand All @@ -111,10 +122,13 @@ describe('CheckoutDeliveryModeComponent', () => {
},
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
{ provide: ActiveCartFacade, useClass: MockCartService },
{ provide: GlobalMessageService, useClass: MockGlobalMessageService },
],
}).compileComponents();

checkoutConfigService = TestBed.inject(CheckoutConfigService);
checkoutDeliveryModesFacade = TestBed.inject(CheckoutDeliveryModesFacade);
globalMessageService = TestBed.inject(GlobalMessageService);
checkoutStepService = TestBed.inject(
CheckoutStepService as Type<CheckoutStepService>
);
Expand Down Expand Up @@ -154,6 +168,25 @@ describe('CheckoutDeliveryModeComponent', () => {
);
});

it('should show error message if setDeliveryMode fail', () => {
const showErrorMessageSpy = spyOn(
globalMessageService,
'add'
).and.callThrough();
checkoutDeliveryModesFacade.setDeliveryMode = createSpy().and.returnValue(
throwError('error')
);

component.changeMode('pickup');

expect(showErrorMessageSpy).toHaveBeenCalledWith(
{
key: 'setDeliveryMode.unknownError',
},
GlobalMessageType.MSG_TYPE_ERROR
);
});

it('should remove pickup from supported delivery modes', () => {
spyOn(checkoutConfigService, 'getPreferredDeliveryMode').and.callThrough();
supportedDeliveryModes$.next([{ code: 'pickup' }]);
Expand Down Expand Up @@ -227,6 +260,18 @@ describe('CheckoutDeliveryModeComponent', () => {
expect(getContinueBtn().nativeElement.disabled).toBe(false);
});

it('should be disabled when setDeliveryMode failed', () => {
checkoutDeliveryModesFacade.setDeliveryMode = createSpy().and.returnValue(
throwError('error')
);

component.changeMode('pickup');

fixture.detectChanges();

expect(getContinueBtn().nativeElement.disabled).toBe(true);
});

it('should call "next" function after being clicked', () => {
spyOn(component, 'next');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { ChangeDetectionStrategy, Component, Optional } from '@angular/core';
import {
UntypedFormBuilder,
UntypedFormGroup,
Expand All @@ -13,6 +13,7 @@ import {
import { ActivatedRoute } from '@angular/router';
import { ActiveCartFacade, CartOutlets } from '@spartacus/cart/base/root';
import { CheckoutDeliveryModesFacade } from '@spartacus/checkout/base/root';
import { GlobalMessageService, GlobalMessageType } from '@spartacus/core';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import {
distinctUntilChanged,
Expand All @@ -31,8 +32,13 @@ import { CheckoutStepService } from '../services/checkout-step.service';
})
export class CheckoutDeliveryModeComponent {
protected busy$ = new BehaviorSubject(false);
protected readonly isSetDeliveryModeHttpErrorSub = new BehaviorSubject(false);

readonly CartOutlets = CartOutlets;

isSetDeliveryModeHttpError$ =
this.isSetDeliveryModeHttpErrorSub.asObservable();

selectedDeliveryModeCode$ = this.checkoutDeliveryModesFacade
.getSelectedDeliveryModeState()
.pipe(
Expand Down Expand Up @@ -84,16 +90,43 @@ export class CheckoutDeliveryModeComponent {
return this.mode.controls['deliveryModeId'].invalid;
}

// TODO(CXSPA-3976): make globalMessageService a required dependency
constructor(
fb: UntypedFormBuilder,
checkoutConfigService: CheckoutConfigService,
activatedRoute: ActivatedRoute,
checkoutStepService: CheckoutStepService,
checkoutDeliveryModesFacade: CheckoutDeliveryModesFacade,
activeCartFacade: ActiveCartFacade,
// eslint-disable-next-line @typescript-eslint/unified-signatures
globalMessageService: GlobalMessageService
);
/**
* @deprecated since 6.2
*/
constructor(
fb: UntypedFormBuilder,
checkoutConfigService: CheckoutConfigService,
activatedRoute: ActivatedRoute,
checkoutStepService: CheckoutStepService,
checkoutDeliveryModesFacade: CheckoutDeliveryModesFacade,
activeCartFacade: ActiveCartFacade
);
constructor(
protected fb: UntypedFormBuilder,
protected checkoutConfigService: CheckoutConfigService,
protected activatedRoute: ActivatedRoute,
protected checkoutStepService: CheckoutStepService,
protected checkoutDeliveryModesFacade: CheckoutDeliveryModesFacade,
protected activeCartFacade: ActiveCartFacade
protected activeCartFacade: ActiveCartFacade,
@Optional() protected globalMessageService?: GlobalMessageService
) {}

changeMode(code: string): void {
changeMode(code: string | undefined): void {
if (!code) {
return;
}

this.busy$.next(true);

this.checkoutDeliveryModesFacade.setDeliveryMode(code).subscribe({
Expand All @@ -110,15 +143,22 @@ export class CheckoutDeliveryModeComponent {
this.checkoutStepService.back(this.activatedRoute);
}

getAriaChecked(code: string): boolean {
getAriaChecked(code: string | undefined): boolean {
return code === this.mode.controls['deliveryModeId'].value;
}

protected onSuccess(): void {
this.isSetDeliveryModeHttpErrorSub.next(false);
this.busy$.next(false);
}

protected onError(): void {
this.globalMessageService?.add(
{ key: 'setDeliveryMode.unknownError' },
GlobalMessageType.MSG_TYPE_ERROR
);

this.isSetDeliveryModeHttpErrorSub.next(true);
this.busy$.next(false);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TestBed } from '@angular/core/testing';
import { ActiveCartFacade } from '@spartacus/cart/base/root';
import { ActiveCartFacade, DeleteCartEvent } from '@spartacus/cart/base/root';
import {
createFrom,
CxEvent,
Expand Down Expand Up @@ -239,4 +239,15 @@ describe(`CheckoutDeliveryAddressEventListener`, () => {
);
});
});

describe(`onCartDeleted`, () => {
it(`DeleteCartEvent should dispatch CheckoutQueryResetEvent`, () => {
mockEventStream$.next(new DeleteCartEvent());

expect(eventService.dispatch).toHaveBeenCalledWith(
{},
CheckoutQueryResetEvent
);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import { Injectable, OnDestroy } from '@angular/core';
import { ActiveCartFacade } from '@spartacus/cart/base/root';
import { ActiveCartFacade, DeleteCartEvent } from '@spartacus/cart/base/root';
import {
DeleteUserAddressEvent,
EventService,
Expand Down Expand Up @@ -47,6 +47,8 @@ export class CheckoutDeliveryAddressEventListener implements OnDestroy {
this.onDeliveryAddressCleared();

this.onUserAddressChange();

this.onCartDeleted();
}

/**
Expand Down Expand Up @@ -129,6 +131,16 @@ export class CheckoutDeliveryAddressEventListener implements OnDestroy {
);
}

protected onCartDeleted(): void {
this.subscriptions.add(
this.eventService
.get(DeleteCartEvent)
.subscribe(() =>
this.eventService.dispatch({}, CheckoutQueryResetEvent)
)
);
}

ngOnDestroy(): void {
this.subscriptions.unsubscribe();
}
Expand Down
11 changes: 11 additions & 0 deletions projects/assets/src/translations/en/delivery-mode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2023 SAP Spartacus team <[email protected]>
*
* SPDX-License-Identifier: Apache-2.0
*/

export const deliveryMode = {
setDeliveryMode: {
unknownError: 'An unknown error occurred. Please contact support.',
},
};
2 changes: 2 additions & 0 deletions projects/assets/src/translations/en/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import { address } from './address';
import { common } from './common';
import { deliveryMode } from './delivery-mode';
import { myAccount } from './my-account';
import { payment } from './payment';
import { pdf } from './pdf';
Expand All @@ -24,4 +25,5 @@ export const en = {
user,
video,
pdf,
deliveryMode,
};
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,5 @@ export const translationChunksConfig: TranslationChunksConfig = {
],
user: ['anonymousConsents', 'loginRegister', 'checkoutLogin', 'authMessages'],
video: ['player'],
deliveryMode: ['setDeliveryMode'],
};

0 comments on commit 16fee09

Please sign in to comment.