Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(redux): add packaging options redux #991

Open
wants to merge 1 commit into
base: dev-main-20-02-24
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/redux/src/__tests__/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@ Object {
"FETCH_COLLECT_POINTS_FAILURE": "@farfetch/blackout-redux/FETCH_COLLECT_POINTS_FAILURE",
"FETCH_COLLECT_POINTS_REQUEST": "@farfetch/blackout-redux/FETCH_COLLECT_POINTS_REQUEST",
"FETCH_COLLECT_POINTS_SUCCESS": "@farfetch/blackout-redux/FETCH_COLLECT_POINTS_SUCCESS",
"FETCH_PACKAGING_OPTIONS_FAILURE": "@farfetch/blackout-redux/FETCH_PACKAGING_OPTIONS_FAILURE",
"FETCH_PACKAGING_OPTIONS_REQUEST": "@farfetch/blackout-redux/FETCH_PACKAGING_OPTIONS_REQUEST",
"FETCH_PACKAGING_OPTIONS_SUCCESS": "@farfetch/blackout-redux/FETCH_PACKAGING_OPTIONS_SUCCESS",
"REMOVE_CHECKOUT_ORDER_CONTEXT_FAILURE": "@farfetch/blackout-redux/REMOVE_CHECKOUT_ORDER_CONTEXT_FAILURE",
"REMOVE_CHECKOUT_ORDER_CONTEXT_REQUEST": "@farfetch/blackout-redux/REMOVE_CHECKOUT_ORDER_CONTEXT_REQUEST",
"REMOVE_CHECKOUT_ORDER_CONTEXT_SUCCESS": "@farfetch/blackout-redux/REMOVE_CHECKOUT_ORDER_CONTEXT_SUCCESS",
Expand Down Expand Up @@ -733,6 +736,8 @@ Object {
"fetchOrderItemAvailableActivitiesFactory": [Function],
"fetchOrderReturnOptions": [Function],
"fetchOrderReturnOptionsFactory": [Function],
"fetchPackagingOptions": [Function],
"fetchPackagingOptionsFactory": [Function],
"fetchPaymentIntent": [Function],
"fetchPaymentIntentCharge": [Function],
"fetchPaymentIntentChargeFactory": [Function],
Expand Down Expand Up @@ -1044,6 +1049,8 @@ Object {
"getOrderReturns": [Function],
"getOrderSummaries": [Function],
"getOrders": [Function],
"getPackagingOptionsError": [Function],
"getPackagingOptionsResult": [Function],
"getPaymentIntentChargeError": [Function],
"getPaymentIntentChargeResult": [Function],
"getPaymentIntentError": [Function],
Expand Down Expand Up @@ -1309,6 +1316,7 @@ Object {
"isLogoutLoading": [Function],
"isOrderFetched": [Function],
"isOrderLoading": [Function],
"isPackagingOptionsLoading": [Function],
"isPaymentIntentChargeLoading": [Function],
"isPaymentIntentFetched": [Function],
"isPaymentIntentLoading": [Function],
Expand Down Expand Up @@ -1477,6 +1485,7 @@ Object {
"@farfetch/blackout-redux/RESET_ORDER_RETURN_OPTIONS_ENTITIES": [Function],
},
"ordersReducer": [Function],
"packagingOptionsReducer": [Function],
"paymentsActionTypes": Object {
"CREATE_PAYMENT_INTENT_CHARGE_FAILURE": "@farfetch/blackout-redux/CREATE_PAYMENT_INTENT_CHARGE_FAILURE",
"CREATE_PAYMENT_INTENT_CHARGE_REQUEST": "@farfetch/blackout-redux/CREATE_PAYMENT_INTENT_CHARGE_REQUEST",
Expand Down
16 changes: 16 additions & 0 deletions packages/redux/src/checkout/actionTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -514,3 +514,19 @@ export const REMOVE_CHECKOUT_ORDER_CONTEXT_REQUEST =
*/
export const REMOVE_CHECKOUT_ORDER_CONTEXT_SUCCESS =
'@farfetch/blackout-redux/REMOVE_CHECKOUT_ORDER_CONTEXT_SUCCESS';

/**
* Action type dispatched when the packaging options request fails.
*/
export const FETCH_PACKAGING_OPTIONS_FAILURE =
'@farfetch/blackout-redux/FETCH_PACKAGING_OPTIONS_FAILURE';
/**
* Action type dispatched when the packaging options request starts.
*/
export const FETCH_PACKAGING_OPTIONS_REQUEST =
'@farfetch/blackout-redux/FETCH_PACKAGING_OPTIONS_REQUEST';
/**
* Action type dispatched when the fetch packaging options request succeeds.
*/
export const FETCH_PACKAGING_OPTIONS_SUCCESS =
'@farfetch/blackout-redux/FETCH_PACKAGING_OPTIONS_SUCCESS';
1 change: 1 addition & 0 deletions packages/redux/src/checkout/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * as checkoutActionTypes from './actionTypes.js';

export * from './actions/index.js';
export * from './actions/factories/index.js';
export * from './packaging/index.js';
export * from './selectors.js';

export {
Expand Down
59 changes: 59 additions & 0 deletions packages/redux/src/checkout/packaging/__tests__/reducer.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as actionTypes from '../../actionTypes.js';
import reducer, * as fromReducer from '../reducer.js';
import type { PackagingOptionsState } from '../types/index.js';

let initialState: PackagingOptionsState;

describe('Packaging Options reducer', () => {
beforeEach(() => {
initialState = fromReducer.INITIAL_STATE;
});

it.each([actionTypes.FETCH_PACKAGING_OPTIONS_REQUEST])(
'should handle %s action type',
actionType => {
expect(reducer(undefined, { type: actionType })).toEqual({
error: initialState.error,
isLoading: true,
result: null,
});
},
);

it.each([actionTypes.FETCH_PACKAGING_OPTIONS_FAILURE])(
'should handle %s action type',
actionType => {
const error = 'foo';
const reducerResult = reducer(undefined, {
payload: { error },
type: actionType,
});
const expectedResult = {
error,
isLoading: false,
result: null,
};

expect(reducerResult).toEqual(expectedResult);
},
);

it.each([actionTypes.FETCH_PACKAGING_OPTIONS_SUCCESS])(
'should handle %s action type',
actionType => {
const result = 'foo';

const reducerResult = reducer(undefined, {
payload: { result },
type: actionType,
});
const expectedResult = {
error: initialState.error,
isLoading: false,
result,
};

expect(reducerResult).toEqual(expectedResult);
},
);
});
47 changes: 47 additions & 0 deletions packages/redux/src/checkout/packaging/__tests__/selectors.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as packagingOptionsReducer from '../reducer.js';
import * as selectors from '../selectors.js';
import { mockPackagingOptionsState } from 'tests/__fixtures__/checkout/index.mjs';
import type { StoreState } from '../../../index.js';

describe('packaging options redux selectors', () => {
beforeEach(jest.clearAllMocks);

it('should get the packaging options result property from state', () => {
const spy = jest.spyOn(packagingOptionsReducer, 'getPackagingOptions');

expect(
selectors.getPackagingOptionsResult(
mockPackagingOptionsState as StoreState,
),
).toEqual(mockPackagingOptionsState.packagingOptions.result);
expect(spy).toHaveBeenCalledWith(
mockPackagingOptionsState.packagingOptions,
);
});

it('should get the packaging options error property from state', () => {
const spy = jest.spyOn(packagingOptionsReducer, 'getPackagingOptions');

expect(
selectors.getPackagingOptionsError(
mockPackagingOptionsState as StoreState,
),
).toEqual(mockPackagingOptionsState.packagingOptions.error);
expect(spy).toHaveBeenCalledWith(
mockPackagingOptionsState.packagingOptions,
);
});

it('should get the packaging options isLoading property from state', () => {
const spy = jest.spyOn(packagingOptionsReducer, 'getPackagingOptions');

expect(
selectors.isPackagingOptionsLoading(
mockPackagingOptionsState as StoreState,
),
).toEqual(mockPackagingOptionsState.packagingOptions.isLoading);
expect(spy).toHaveBeenCalledWith(
mockPackagingOptionsState.packagingOptions,
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import * as actionTypes from '../../../actionTypes.js';
import {
type Config,
type GetPackagingOptions,
type GetPackagingOptionsQuery,
type PackagingOption,
toBlackoutError,
} from '@farfetch/blackout-client';
import type { Dispatch } from 'redux';

/**
* Method responsible for get all packaging options.
*
* @param getPackagingOptions - Get all packaging options.
*
* @returns Thunk factory.
*/
const fetchPackagingOptionsFactory =
(getPackagingOptions: GetPackagingOptions) =>
(query: GetPackagingOptionsQuery, config?: Config) =>
async (dispatch: Dispatch): Promise<PackagingOption[]> => {
try {
dispatch({
type: actionTypes.FETCH_PACKAGING_OPTIONS_REQUEST,
});

const result = await getPackagingOptions(query, config);

dispatch({
payload: result,
type: actionTypes.FETCH_PACKAGING_OPTIONS_SUCCESS,
});

return result;
} catch (error) {
const errorAsBlackoutError = toBlackoutError(error);

dispatch({
payload: { error: errorAsBlackoutError },
type: actionTypes.FETCH_PACKAGING_OPTIONS_FAILURE,
});

throw errorAsBlackoutError;
}
};

export default fetchPackagingOptionsFactory;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Packaging options actions factories.
*/

export { default as fetchPackagingOptionsFactory } from './fetchPackagingOptionsFactory.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { fetchPackagingOptionsFactory } from './factories/index.js';
import { getPackagingOptions } from '@farfetch/blackout-client';

/**
* Fetch all packaging options.
*/
export default fetchPackagingOptionsFactory(getPackagingOptions);
5 changes: 5 additions & 0 deletions packages/redux/src/checkout/packaging/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/**
* Packaging actions.
*/

export { default as fetchPackagingOptions } from './fetchPackagingOptions.js';
5 changes: 5 additions & 0 deletions packages/redux/src/checkout/packaging/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export * from './actions/index.js';
export * from './actions/factories/index.js';
export * from './types/index.js';
export { default as packagingOptionsReducer } from './reducer.js';
export * from './selectors.js';
69 changes: 69 additions & 0 deletions packages/redux/src/checkout/packaging/reducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import * as actionTypes from './../actionTypes.js';
import { type AnyAction, combineReducers } from 'redux';
import { createReducerWithResult } from '../../helpers/reducerFactory.js';
import type { PackagingOptionsState } from './index.js';

export const INITIAL_STATE: PackagingOptionsState = {
error: null,
result: null,
isLoading: false,
};

export const packagingOptions = createReducerWithResult(
'FETCH_PACKAGING_OPTIONS',
INITIAL_STATE,
actionTypes,
);

const error = (
state = INITIAL_STATE.error,
action: AnyAction,
): PackagingOptionsState['error'] => {
switch (action.type) {
case actionTypes.FETCH_PACKAGING_OPTIONS_FAILURE:
return action.payload.error;
case actionTypes.FETCH_PACKAGING_OPTIONS_REQUEST:
return INITIAL_STATE.error;
default:
return state;
}
};

const isLoading = (
state = INITIAL_STATE.isLoading,
action: AnyAction,
): PackagingOptionsState['isLoading'] => {
switch (action.type) {
case actionTypes.FETCH_PACKAGING_OPTIONS_REQUEST:
return true;
case actionTypes.FETCH_PACKAGING_OPTIONS_SUCCESS:
case actionTypes.FETCH_PACKAGING_OPTIONS_FAILURE:
return INITIAL_STATE.isLoading;
default:
return state;
}
};

const result = (
state = INITIAL_STATE.result,
action: AnyAction,
): PackagingOptionsState['result'] => {
switch (action.type) {
case actionTypes.FETCH_PACKAGING_OPTIONS_SUCCESS:
return action.payload.result;
default:
return state;
}
};

export const getPackagingOptions = (
state: PackagingOptionsState,
): PackagingOptionsState => state;

const packagingOptionsReducer = combineReducers({
result,
error,
isLoading,
});

export default packagingOptionsReducer;
33 changes: 33 additions & 0 deletions packages/redux/src/checkout/packaging/selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { getPackagingOptions } from './reducer.js';
import type { PackagingOptionsState, StoreState } from '../../index.js';

/**
* Returns the packaging options.
*
* @param state - Application state.
*
* @returns Packaging Options result.
*/
export const getPackagingOptionsResult = (state: StoreState) =>
getPackagingOptions(state.packagingOptions as PackagingOptionsState).result;

/**
* Returns the loading status for the packaging options operation.
*
* @param state - Application state.
*
* @returns Packaging Options operation Loading status.
*/
export const isPackagingOptionsLoading = (state: StoreState) =>
getPackagingOptions(state.packagingOptions as PackagingOptionsState)
.isLoading;

/**
* Returns the error status for the packaging options operation.
*
* @param state - Application state.
*
* @returns Packaging Options operation error.
*/
export const getPackagingOptionsError = (state: StoreState) =>
getPackagingOptions(state.packagingOptions as PackagingOptionsState).error;
7 changes: 7 additions & 0 deletions packages/redux/src/checkout/packaging/types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { BlackoutError, PackagingOption } from '@farfetch/blackout-client';

export type PackagingOptionsState = {
result: PackagingOption[] | null;
isLoading: boolean;
error: BlackoutError | null;
};
3 changes: 3 additions & 0 deletions packages/redux/src/entities/schemas/packagingOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { schema } from 'normalizr';

export default new schema.Entity('packagingOptions');
1 change: 1 addition & 0 deletions packages/redux/src/entities/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ export * from './user.types.js';
export * from './raffle.types.js';
export * from './raffleParticipations.types.js';
export * from './raffleEstimation.types.js';
export * from './packagingOptions.types.js';
3 changes: 3 additions & 0 deletions packages/redux/src/entities/types/packagingOptions.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import type { PackagingOption } from '@farfetch/blackout-client';

export type PackagingOptionsEntity = PackagingOption[];
Loading
Loading