diff --git a/libs/cart/state/src/effects/cart-payment-processor.effects.ts b/libs/cart/state/src/effects/cart-payment-processor.effects.ts index 390c540ecb..83fae6d460 100644 --- a/libs/cart/state/src/effects/cart-payment-processor.effects.ts +++ b/libs/cart/state/src/effects/cart-payment-processor.effects.ts @@ -9,34 +9,36 @@ import { ofType, } from '@ngrx/effects'; import { + Observable, + combineLatest, defer, of, } from 'rxjs'; -import { - switchMap, - map, - catchError, -} from 'rxjs/operators'; +import { switchMap } from 'rxjs/operators'; +import { DaffCart } from '@daffodil/cart'; import { - DaffCartPaymentMethod, - DaffCart, - DaffCartAddress, - DaffCartStorageService, -} from '@daffodil/cart'; -import { + DaffCartDriverResolveService, DaffCartPaymentDriver, DaffCartPaymentServiceInterface, } from '@daffodil/cart/driver'; -import { catchAndArrayifyErrors } from '@daffodil/core'; +import { + DaffError, + catchAndArrayifyErrors, +} from '@daffodil/core'; import { ErrorTransformer } from '@daffodil/core/state'; -import { DaffPaymentResponse } from '@daffodil/payment'; +import { + DaffPaymentRequest, + DaffPaymentResponse, +} from '@daffodil/payment'; +import { DaffPaymentDriverInterface } from '@daffodil/payment/driver'; import { DAFF_PAYMENT_PROCESSOR_COLLECTION, DaffPaymentProcessorCollection, DaffPaymentGenerateToken, DaffPaymentGenerateTokenFailure, DAFF_PAYMENT_ERROR_MATCHER, + DaffPaymentGenerateTokenPayload, } from '@daffodil/payment/state'; import { @@ -45,19 +47,65 @@ import { } from '../actions/public_api'; import { DAFF_CART_ERROR_MATCHER } from '../injection-tokens/public_api'; +/** + * Performs a payment update on the current cart. + * + * @param payload The generate token request. + * @param deps DI deps. + * @param cbs Return the actions and/or perform custom behavior in response to each particular case. + */ +export function daffCartPaymentProcessorUpdate< + Cart extends DaffCart = DaffCart, + Request extends DaffPaymentRequest = DaffPaymentRequest, + Response extends DaffPaymentResponse = DaffPaymentResponse, + Success = unknown, + PaymentFailure = unknown, + UpdateFailure = unknown +>( + payload: DaffPaymentGenerateTokenPayload, + deps: { + cartDriver: DaffCartPaymentServiceInterface; + paymentDriver: DaffPaymentDriverInterface; + cartResolver: DaffCartDriverResolveService; + }, + cbs: { + success: (resp: Cart) => Observable; + paymentFailure: (errors: Array) => Observable; + updateFailure: (errors: Array) => Observable; + }, +) { + return defer(() => + combineLatest([ + deps.paymentDriver.generateToken(payload.request), + deps.cartResolver.getCartIdOrFail(), + ]).pipe( + switchMap(([response, cartId]) => + deps.cartDriver.update( + cartId, + { + method: response.method, + payment_info: response.data, + }, + payload.address, + ).pipe( + switchMap(cbs.success), + catchAndArrayifyErrors(cbs.updateFailure), + ), + ), + catchAndArrayifyErrors(cbs.paymentFailure), + ), + ); +} + @Injectable() -export class DaffCartPaymentProcessorEffects< - T extends DaffCartPaymentMethod = DaffCartPaymentMethod, - V extends DaffCart = DaffCart, - R extends DaffCartAddress = DaffCartAddress, -> { +export class DaffCartPaymentProcessorEffects { constructor( private actions$: Actions, @Inject(DAFF_PAYMENT_PROCESSOR_COLLECTION) private processors: DaffPaymentProcessorCollection, @Inject(DAFF_CART_ERROR_MATCHER) private errorMatcher: ErrorTransformer, @Inject(DAFF_PAYMENT_ERROR_MATCHER) private paymentErrorMatcher: ErrorTransformer, - @Inject(DaffCartPaymentDriver) private driver: DaffCartPaymentServiceInterface, - private storage: DaffCartStorageService, + @Inject(DaffCartPaymentDriver) private driver: DaffCartPaymentServiceInterface, + private cartResolver: DaffCartDriverResolveService, private injector: Injector, ) {} @@ -68,20 +116,18 @@ export class DaffCartPaymentProcessorEffects< switchMap((action: DaffPaymentGenerateToken) => // create a new inner observable to prevent the effects obs // from completing on outer catch error - defer(() => - this.injector.get(this.processors[action.request.kind].driver).generateToken(action.request).pipe( - map(e => [e, action]), - switchMap(([response, act]: [DaffPaymentResponse, DaffPaymentGenerateToken]) => - this.driver.update(this.storage.getCartId(), { - method: response.method, - payment_info: response.data, - }, act.address).pipe( - map((resp: V) => new DaffCartPaymentUpdateSuccess(resp)), - catchAndArrayifyErrors(error => of(new DaffCartPaymentUpdateFailure(error.map(this.errorMatcher)))), - ), - ), - catchAndArrayifyErrors(error => of(new DaffPaymentGenerateTokenFailure(this.paymentErrorMatcher(error[0])))), - ), + daffCartPaymentProcessorUpdate( + action, + { + paymentDriver: this.injector.get(this.processors[action.request.kind].driver), + cartDriver: this.driver, + cartResolver: this.cartResolver, + }, + { + success: (resp) => of(new DaffCartPaymentUpdateSuccess(resp)), + paymentFailure: (errors) => of(new DaffPaymentGenerateTokenFailure(this.paymentErrorMatcher(errors[0]))), + updateFailure: (errors) => of(new DaffCartPaymentUpdateFailure(errors.map(this.errorMatcher))), + }, ), ), )); diff --git a/libs/cart/state/src/effects/public_api.ts b/libs/cart/state/src/effects/public_api.ts new file mode 100644 index 0000000000..a42e38c1b2 --- /dev/null +++ b/libs/cart/state/src/effects/public_api.ts @@ -0,0 +1 @@ +export { daffCartPaymentProcessorUpdate } from './cart-payment-processor.effects'; diff --git a/libs/cart/state/src/public_api.ts b/libs/cart/state/src/public_api.ts index c3699b3e82..a91d69db40 100644 --- a/libs/cart/state/src/public_api.ts +++ b/libs/cart/state/src/public_api.ts @@ -1,5 +1,6 @@ export * from './actions/public_api'; export * from './cart-retrieval/public_api'; +export * from './effects/public_api'; export * from './selectors/public_api'; export * from './reducers/public_api'; export * from './injection-tokens/public_api'; diff --git a/libs/payment/state/src/actions/payment.actions.ts b/libs/payment/state/src/actions/payment.actions.ts index a3c42b3ecd..98bf708c36 100644 --- a/libs/payment/state/src/actions/payment.actions.ts +++ b/libs/payment/state/src/actions/payment.actions.ts @@ -21,10 +21,11 @@ export enum DaffPaymentActionTypes { * * @param query The payment query. */ -export interface DaffPaymentGenerateToken extends Action { +export interface DaffPaymentGenerateTokenPayload { readonly request: T; readonly address?: DaffPersonalAddress | DaffIdentifiable; } +export interface DaffPaymentGenerateToken extends DaffPaymentGenerateTokenPayload, Action {} /** * Indicates a successful generation of a payment token.