@shopgate/pwa-common-commerce
Version:
Commerce library for the Shopgate Connect PWA.
126 lines (121 loc) • 3.46 kB
JavaScript
import "core-js/modules/es.array.reduce.js";
import { ENOTFOUND } from '@shopgate/pwa-core/constants/Pipeline';
import { PRODUCT_LIFETIME, REQUEST_PRODUCT, RECEIVE_PRODUCT, RECEIVE_PRODUCTS, ERROR_PRODUCT, UPDATE_METADATA, EXPIRE_PRODUCT_BY_ID, DELETE_PRODUCTS_BY_IDS, RECEIVE_PRODUCT_RELATIONS, EXPIRE_PRODUCT_DATA } from "../constants";
import handleProductCollection from "./helpers/handleProductCollection";
/**
* Stores products by their ID.
* @param {Object} [state={}] The current state.
* @param {Object} action The action object.
* @return {Object} The new state.
*/
export default function productsById(state = {}, action = {}) {
switch (action.type) {
case RECEIVE_PRODUCTS:
return {
...state,
...handleProductCollection(action.products)
};
case RECEIVE_PRODUCT_RELATIONS:
return {
...state,
...handleProductCollection(action.payload.relations)
};
case REQUEST_PRODUCT:
return {
...state,
[action.productId]: {
...state[action.productId],
isFetching: true,
expires: 0
}
};
case RECEIVE_PRODUCT:
return {
...state,
[action.productId]: {
...state[action.productId],
productData: action.productData,
isFetching: false,
expires: Date.now() + PRODUCT_LIFETIME
}
};
case ERROR_PRODUCT:
if (action.errorCode === ENOTFOUND) {
// Remove the entry from the state when noting was found for the productId.
const {
[action.productId]: ignore,
...rest
} = state;
return rest;
}
return {
...state,
[action.productId]: {
...state[action.productId],
isFetching: false
}
};
case UPDATE_METADATA:
{
const {
productData = {}
} = state[action.productId];
// Merge the given metadata with the existing metadata.
const metadata = {
...productData.metadata,
...action.metadata
};
// Put the metadata back into the productData.
const updatedProductData = {
...productData,
metadata
};
// Put the updated product back into the state.
return {
...state,
[action.productId]: {
...state[action.productId],
productData: updatedProductData
}
};
}
case EXPIRE_PRODUCT_BY_ID:
return {
...state,
[action.productId]: {
...state[action.productId],
expires: 0
}
};
// Mark all product data as expired
case EXPIRE_PRODUCT_DATA:
{
if (Array.isArray(action.scopes) && action.scopes.includes('price')) {
return Object.keys(state).reduce((accumulator, productId) => {
accumulator[productId] = {
...accumulator[productId],
expires: 0
};
return accumulator;
}, {
...state
});
}
return state;
}
case DELETE_PRODUCTS_BY_IDS:
{
const nextState = {
...state
};
if (Array.isArray(action?.productIds)) {
action.productIds.forEach(productId => {
delete nextState[productId];
});
}
return nextState;
}
default:
return state;
}
}