Skip to content

Commit

Permalink
feat(cart): add cart retrieval action support (#2557)
Browse files Browse the repository at this point in the history
  • Loading branch information
griest024 committed Nov 30, 2023
1 parent 40cf496 commit 98301f8
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 0 deletions.
77 changes: 77 additions & 0 deletions libs/cart/state/src/cart-retrieval/get-response.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { TestBed } from '@angular/core/testing';
import { Action } from '@ngrx/store';

import { DaffCart } from '@daffodil/cart';
import {
DaffCartRetrievalAction,
DaffCartRetrievalActionInjection,
} from '@daffodil/cart/state';
import { DaffCartFactory } from '@daffodil/cart/testing';

import { daffCartRetrievalGetResponse } from './get-response';

class DirectAction implements DaffCartRetrievalAction {
type = 'direct';
constructor(public payload: DaffCart) {}
}

class TransformAction implements Action {
type = 'transform';
constructor(public response: DaffCart) {}
}

describe('@daffodil/cart/state | daffCartRetrievalGetResponse', () => {
let result: Partial<DaffCart> | null;
let actions: DaffCartRetrievalActionInjection[];
let cartFactory: DaffCartFactory;
let mockCart: DaffCart;

beforeEach(() => {
cartFactory = TestBed.inject(DaffCartFactory);

mockCart = cartFactory.create();
actions = [
{ type: 'direct' },
{ type: 'transform', transform: <any>((action: TransformAction) => action.response) },
];
});

describe('when the action is not a recognized retrieval action', () => {
beforeEach(() => {
result = daffCartRetrievalGetResponse(
{ type: 'unknown' },
actions,
);
});

it('should return null', () => {
expect(result).toBeNull();
});
});

describe('when the action is direct', () => {
beforeEach(() => {
result = daffCartRetrievalGetResponse(
new DirectAction(mockCart),
actions,
);
});

it('should return the cart', () => {
expect(result).toEqual(mockCart);
});
});

describe('when the action is transform', () => {
beforeEach(() => {
result = daffCartRetrievalGetResponse(
new TransformAction(mockCart),
actions,
);
});

it('should return the cart', () => {
expect(result).toEqual(mockCart);
});
});
});
22 changes: 22 additions & 0 deletions libs/cart/state/src/cart-retrieval/get-response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Action } from '@ngrx/store';

import { DaffCart } from '@daffodil/cart';

import {
DaffCartRetrievalAction,
DaffCartRetrievalActionInjection,
DaffCartRetrievalActionTransformedInjection,
} from './type';

/**
* Gets the cart from the passed action if it is a recognized retrieval action and applying the transformation if needed.
*/
export function daffCartRetrievalGetResponse<T extends DaffCart = DaffCart>(action: Action, retrievalActions: DaffCartRetrievalActionInjection[]): Partial<T> | null {
const actionInjection = retrievalActions.find(({ type }) => type === action.type);

if (actionInjection) {
return (<DaffCartRetrievalActionTransformedInjection>actionInjection).transform?.<T>(action) || (<DaffCartRetrievalAction<T>>action).payload;
}

return null;
}
3 changes: 3 additions & 0 deletions libs/cart/state/src/cart-retrieval/public_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './token';
export * from './type';
export * from './get-response';
21 changes: 21 additions & 0 deletions libs/cart/state/src/cart-retrieval/token.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {
InjectionToken,
ValueProvider,
} from '@angular/core';

import { DaffCartRetrievalActionInjection } from './type';

/**
* A token to hold {@link DaffCartRetrievalActionInjection}s.
*/
export const DAFF_CART_RETRIEVAL_ACTIONS = new InjectionToken<DaffCartRetrievalActionInjection[]>('DAFF_CART_RETRIEVAL_ACTIONS', { factory: () => []});

/**
* A provider function for {@link DAFF_CART_RETRIEVAL_ACTIONS}.
*/
export const daffCartProvideRetrievalActions = (...actions: DaffCartRetrievalActionInjection[]): ValueProvider[] =>
actions.map((action) => ({
provide: DAFF_CART_RETRIEVAL_ACTIONS,
useValue: action,
multi: true,
}));
46 changes: 46 additions & 0 deletions libs/cart/state/src/cart-retrieval/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Action } from '@ngrx/store';

import { DaffCart } from '@daffodil/cart';

/**
* Represents an action that loads a portion of the cart.
*/
export interface DaffCartRetrievalAction<T extends DaffCart = DaffCart> extends Action {
readonly payload: Partial<T>;
}

/**
* Represents an injection of a retrieval action that implements the {@link DaffCartRetrievalAction} interface
* and therefore does not need transformation.
* If the injected action needs transformation, use {@link DaffCartRetrievalActionTransformedInjection}
*/
export interface DaffCartRetrievalActionDirectInjection<T extends DaffCartRetrievalAction = DaffCartRetrievalAction> {
/**
* The action type.
*/
type: T['type'];
}

/**
* Represents an injection of a retrieval action that doesn't implement the {@link DaffCartRetrievalAction} interface.
* Contains a way to get the cart from the action.
*/
export interface DaffCartRetrievalActionTransformedInjection<T extends Action = Action> {
/**
* The action type.
*/
type: T['type'];

/**
* A function that gets the retrieved cart from the action.
*/
transform: <TCart extends DaffCart = DaffCart>(action: T) => Partial<TCart>;
}

/**
* Represents an injection of a cart retrieval action.
* These actions are typically dispatched when an operation that mutates or loads the cart completes.
* Actions provided to {@link DAFF_CART_RETRIEVAL_ACTIONS} are natively understood by Daffodil reducers and will automatically
* populate the appropriate pieces of state when they are dispatched.
*/
export type DaffCartRetrievalActionInjection = DaffCartRetrievalActionDirectInjection | DaffCartRetrievalActionTransformedInjection;
1 change: 1 addition & 0 deletions libs/cart/state/src/public_api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './actions/public_api';
export * from './cart-retrieval/public_api';
export * from './selectors/public_api';
export * from './reducers/public_api';
export * from './models/public_api';
Expand Down

0 comments on commit 98301f8

Please sign in to comment.