Skip to content

Commit

Permalink
fix: display error message on PaymentType ClassMismatchError (#17641)
Browse files Browse the repository at this point in the history
CXSPA-3334

Error message is displayed and loader spinner is now hidden when server returns error 400 ClassMismatchError.

BREAKING CHANGE: 

GlobalMessageService has been added in constructor
  • Loading branch information
FollowTheFlo authored Jul 19, 2023
1 parent 87fd0b0 commit 377f2b5
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ <h2 class="cx-checkout-title d-none d-lg-block d-xl-block">
</ng-container>

<ng-template #loading>
<div class="cx-spinner">
<div class="cx-spinner" *ngIf="!paymentTypesError">
<cx-spinner></cx-spinner>
</div>
</ng-template>
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { PaymentType } from '@spartacus/cart/base/root';
import { CheckoutPaymentTypeFacade } from '@spartacus/checkout/b2b/root';
import { CheckoutStepService } from '@spartacus/checkout/base/components';
import { CheckoutStepType } from '@spartacus/checkout/base/root';
import { I18nTestingModule, QueryState } from '@spartacus/core';
import {
GlobalMessageService,
I18nTestingModule,
QueryState,
} from '@spartacus/core';
import { BehaviorSubject, of } from 'rxjs';
import { take } from 'rxjs/operators';
import { CheckoutPaymentTypeComponent } from './checkout-payment-type.component';
Expand All @@ -18,6 +22,9 @@ import createSpy = jasmine.createSpy;
})
class MockSpinnerComponent {}

class MockGlobalMessageService {
add = createSpy();
}
class MockCheckoutPaymentTypeService
implements Partial<CheckoutPaymentTypeFacade>
{
Expand Down Expand Up @@ -92,6 +99,10 @@ describe('CheckoutOnePaymentTypeComponent', () => {
useClass: MockCheckoutStepService,
},
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
{
provide: GlobalMessageService,
useClass: MockGlobalMessageService,
},
],
}).compileComponents();

Expand Down Expand Up @@ -145,6 +156,10 @@ describe('CheckoutPaymentTypeComponent', () => {
useClass: MockCheckoutStepService,
},
{ provide: ActivatedRoute, useValue: mockActivatedRoute },
{
provide: GlobalMessageService,
useClass: MockGlobalMessageService,
},
],
}).compileComponents();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ChangeDetectionStrategy,
Component,
ElementRef,
Optional,
ViewChild,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
Expand All @@ -18,9 +19,22 @@ import {
} from '@spartacus/checkout/b2b/root';
import { CheckoutStepService } from '@spartacus/checkout/base/components';
import { CheckoutStepType } from '@spartacus/checkout/base/root';
import { getLastValueSync, isNotUndefined } from '@spartacus/core';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { distinctUntilChanged, filter, map, tap } from 'rxjs/operators';
import {
GlobalMessageService,
GlobalMessageType,
HttpErrorModel,
OccHttpErrorType,
getLastValueSync,
isNotUndefined,
} from '@spartacus/core';
import { BehaviorSubject, Observable, combineLatest, of } from 'rxjs';
import {
catchError,
distinctUntilChanged,
filter,
map,
tap,
} from 'rxjs/operators';

@Component({
selector: 'cx-payment-type',
Expand All @@ -34,6 +48,7 @@ export class CheckoutPaymentTypeComponent {
protected busy$ = new BehaviorSubject<boolean>(false);

typeSelected?: string;
paymentTypesError = false;

isUpdating$ = combineLatest([
this.busy$,
Expand All @@ -45,8 +60,24 @@ export class CheckoutPaymentTypeComponent {
distinctUntilChanged()
);

paymentTypes$: Observable<PaymentType[]> =
this.checkoutPaymentTypeFacade.getPaymentTypes();
paymentTypes$: Observable<PaymentType[]> = this.checkoutPaymentTypeFacade
.getPaymentTypes()
.pipe(
tap(() => (this.paymentTypesError = false)),
catchError((error: HttpErrorModel) => {
if (
error.details?.[0]?.type === OccHttpErrorType.CLASS_MISMATCH_ERROR &&
this.globalMessageService
) {
this.globalMessageService.add(
{ key: 'httpHandlers.forbidden' },
GlobalMessageType.MSG_TYPE_ERROR
);
this.paymentTypesError = true;
}
return of([]);
})
);

typeSelected$: Observable<PaymentType> = combineLatest([
this.checkoutPaymentTypeFacade.getSelectedPaymentTypeState().pipe(
Expand Down Expand Up @@ -105,10 +136,30 @@ export class CheckoutPaymentTypeComponent {
distinctUntilChanged()
);

// TODO(CXSPA-3334): make globalMessageService a required dependency
constructor(
checkoutPaymentTypeFacade: CheckoutPaymentTypeFacade,
checkoutStepService: CheckoutStepService,
activatedRoute: ActivatedRoute,
// eslint-disable-next-line @typescript-eslint/unified-signatures
globalMessageService?: GlobalMessageService
);

/**
* @deprecated since 6.3
*/
constructor(
checkoutPaymentTypeFacade: CheckoutPaymentTypeFacade,
checkoutStepService: CheckoutStepService,
activatedRoute: ActivatedRoute,
globalMessageService: GlobalMessageService
);

constructor(
protected checkoutPaymentTypeFacade: CheckoutPaymentTypeFacade,
protected checkoutStepService: CheckoutStepService,
protected activatedRoute: ActivatedRoute
protected activatedRoute: ActivatedRoute,
@Optional() protected globalMessageService?: GlobalMessageService
) {}

changeType(code: string): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ import {
CommandService,
CommandStrategy,
EventService,
HttpErrorModel,
OCC_USER_ID_ANONYMOUS,
Query,
QueryNotifier,
QueryService,
QueryState,
UserIdService,
} from '@spartacus/core';
import { combineLatest, Observable } from 'rxjs';
import { filter, map, switchMap, take, tap } from 'rxjs/operators';
import { Observable, combineLatest, of, throwError } from 'rxjs';
import { concatMap, filter, map, switchMap, take, tap } from 'rxjs/operators';
import { CheckoutPaymentTypeConnector } from '../connectors/checkout-payment-type/checkout-payment-type.connector';

@Injectable()
Expand Down Expand Up @@ -119,7 +120,14 @@ export class CheckoutPaymentTypeService implements CheckoutPaymentTypeFacade {
}

getPaymentTypes(): Observable<PaymentType[]> {
return this.getPaymentTypesState().pipe(map((state) => state.data ?? []));
return this.getPaymentTypesState().pipe(
concatMap((state) =>
(state?.error as HttpErrorModel)
? throwError(state.error as HttpErrorModel)
: of(state)
),
map((state) => state.data ?? [])
);
}

setPaymentType(
Expand Down
1 change: 1 addition & 0 deletions projects/core/src/util/occ-http-error-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

export declare const enum OccHttpErrorType {
NOT_FOUND_ERROR = 'NotFoundError',
CLASS_MISMATCH_ERROR = 'ClassMismatchError',
}

export declare const enum OccHttpErrorReason {
Expand Down

0 comments on commit 377f2b5

Please sign in to comment.