@twreporter/redux
Version:
redux actions and reducers for twreporter website
268 lines (257 loc) • 10.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fetchAFullTopic = fetchAFullTopic;
exports.fetchFeatureTopic = fetchFeatureTopic;
exports.fetchTopics = fetchTopics;
var _url2 = require("../utils/url");
var _apiConfig = _interopRequireDefault(require("../constants/api-config"));
var _apiEndpoints = _interopRequireDefault(require("../constants/api-endpoints"));
var _axios = _interopRequireDefault(require("axios"));
var _errorActionCreators = _interopRequireDefault(require("../actions/error-action-creators"));
var _pagination = _interopRequireDefault(require("../utils/pagination"));
var _reduxStateFieldNames = _interopRequireDefault(require("../constants/redux-state-field-names"));
var _actionTypes = _interopRequireDefault(require("../constants/action-types"));
var _get = _interopRequireDefault(require("lodash/get"));
var _isInteger = _interopRequireDefault(require("lodash/isInteger"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
// lodash
var _ = {
get: _get["default"],
isInteger: _isInteger["default"]
};
var pageToOffset = _pagination["default"].pageToOffset;
/**
* Fetch a full topic, whose assets like relateds, leading_video ...etc are all complete,
* @param {string} slug - slug of topic
* @param {number} [timeout=apiConfig.timeout] - request api timeout
* @return {import('../typedef').Thunk} async action creator
*/
function fetchAFullTopic(slug) {
var timeout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _apiConfig["default"].timeout;
return function (dispatch, getState) {
var entities = _reduxStateFieldNames["default"].entities,
topicsInEntities = _reduxStateFieldNames["default"].topicsInEntities;
var state = getState();
var topicId = _.get(state, [entities, topicsInEntities, 'slugToId', slug], '');
var topic = _.get(state, [entities, topicsInEntities, 'byId', topicId], null);
if (_.get(topic, 'full', false)) {
var successAction = {
type: _actionTypes["default"].selectedTopic.read.alreadyExists,
payload: {
topic: topic
}
};
dispatch(successAction);
return Promise.resolve(successAction);
}
var apiOrigin = _.get(state, [_reduxStateFieldNames["default"].origins, 'api']);
var path = "/v2/".concat(_apiEndpoints["default"].topics, "/").concat(slug);
var params = {
full: 'true'
};
// Start to get topics
dispatch({
type: _actionTypes["default"].selectedTopic.read.request,
payload: {
slug: slug
}
});
return _axios["default"].get((0, _url2.formURL)(apiOrigin, path, params), {
timeout: timeout
}).then(function (response) {
var successAction = {
type: _actionTypes["default"].selectedTopic.read.success,
payload: {
topic: _.get(response, 'data.data', {})
}
};
dispatch(successAction);
return successAction;
})["catch"](function (error) {
var failAction = _errorActionCreators["default"].axios(error, _actionTypes["default"].selectedTopic.read.failure);
failAction.payload['slug'] = slug;
dispatch(failAction);
return Promise.reject(failAction);
});
};
}
/**
* @param {Function} dispatch - Redux store dispatch function
* @param {string} origin - URL origin
* @param {string} path - URL path
* @param {object} params - URL params
* @param {string} successActionType
* @param {number} timeout - request api timeout
* @return {Promise} resolve with success action or reject with fail action
*/
function _fetchTopics(dispatch, origin, path, params, successActionType, timeout) {
// Start to get topics
var url = (0, _url2.formURL)(origin, path, params);
dispatch({
type: _actionTypes["default"].topics.read.request,
url: url
});
return _axios["default"].get(url, {
timeout: timeout
}).then(function (response) {
var meta = _.get(response, 'data.data.meta', {});
var total = meta.total,
offset = meta.offset,
limit = meta.limit;
var successAction = {
type: successActionType,
payload: {
items: _.get(response, 'data.data.records', []),
total: total,
limit: limit,
offset: offset
}
};
dispatch(successAction);
return successAction;
})["catch"](function (error) {
var failAction = _errorActionCreators["default"].axios(error, _actionTypes["default"].topics.read.failure);
dispatch(failAction);
return Promise.reject(failAction);
});
}
/**
* Fetch topics(only containing meta properties),
* and it will load more if (total > items you have currently).
*
* @param {number} [page=1]
* @param {number} [nPerPage=5]
* @param {number} [timeout=apiConfig.timeout] - request api timeout
* @return {import('../typedef').Thunk} async action creator
*/
function fetchTopics() {
var page = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
var nPerPage = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 5;
var timeout = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _apiConfig["default"].timeout;
return function (dispatch, getState) {
/* If nPerPage number is invalid, return a Promise.reject(err) */
if (!_.isInteger(nPerPage) || nPerPage <= 0) {
var failAction = _errorActionCreators["default"].preRequestValidation({
nPerPage: "value must be an interger larger than 0, but is ".concat(nPerPage)
}, _actionTypes["default"].topics.read.failure);
dispatch(failAction);
return Promise.reject(failAction);
}
/* If page number is invalid, , return a Promise.reject(err) */
if (!_.isInteger(page) || page <= 0) {
var _failAction = _errorActionCreators["default"].preRequestValidation({
page: "value must be an interger larger than 0, but is ".concat(page)
}, _actionTypes["default"].topics.read.failure);
dispatch(_failAction);
return Promise.reject(_failAction);
}
/* construct request path */
var _pageToOffset = pageToOffset({
page: page,
nPerPage: nPerPage
}),
limit = _pageToOffset.limit,
offset = _pageToOffset.offset;
var state = getState();
if (_.get(state, [_reduxStateFieldNames["default"].topicList, 'items', page, 'length'], 0) > 0) {
var action = {
type: _actionTypes["default"].topics.read.alreadyExists,
payload: {
page: page,
nPerPage: nPerPage
}
};
dispatch(action);
return Promise.resolve(action);
}
var apiOrigin = _.get(state, [_reduxStateFieldNames["default"].origins, 'api']);
var path = "/v2/".concat(_apiEndpoints["default"].topics);
var params = {
limit: limit,
offset: offset
};
return _fetchTopics(dispatch, apiOrigin, path, params, _actionTypes["default"].topics.read.success, timeout);
};
}
/**
* This function fetch the latest topic, and three related posts of that topic.
*
* @param {number} [timeout=apiConfig.timeout] - request api timeout
* @return {import('../typedef').Thunk} async action creator
*/
function fetchFeatureTopic() {
var timeout = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _apiConfig["default"].timeout;
return function (dispatch, getState) {
var state = getState();
if (_.get(state, [_reduxStateFieldNames["default"].featureTopic, 'id'])) {
var action = {
type: _actionTypes["default"].featureTopic.read.alreadyExists
};
dispatch(action);
return Promise.resolve(action);
}
var apiOrigin = _.get(state, [_reduxStateFieldNames["default"].origins, 'api']);
var url = (0, _url2.formURL)(apiOrigin, "/v2/".concat(_apiEndpoints["default"].topics), {
limit: 1,
offset: 0
});
// dispatch request action
dispatch({
type: _actionTypes["default"].featureTopic.read.request
});
return _axios["default"]
// fetch the latest topic as feature topic
.get(url, {
timeout: timeout
}).then(function (response) {
var topic = _.get(response, 'data.data.records.0', {});
return topic;
})
// fetch feature topic's latest three related posts
.then(function (topic) {
var allRelatedIds = _.get(topic, 'relateds', []);
var threeRelatedIds = Array.isArray(allRelatedIds) ? allRelatedIds.slice(0, 3) : [];
if (threeRelatedIds.length > 0) {
var _url = (0, _url2.formURL)(apiOrigin, "/v2/".concat(_apiEndpoints["default"].posts), {
id: threeRelatedIds
});
return Promise.all([topic, _axios["default"].get(_url, {
timeout: timeout
}).then(function (res) {
var relatedPosts = _.get(res, 'data.data.records', []);
// Ensure the order of returned related posts is the same with topic landing page's order,
// since API endpoint /v2/posts will sort the posts automatically by `published_date` in descending order.
return relatedPosts.length < 2 ? relatedPosts : threeRelatedIds.map(function (id) {
return relatedPosts.find(function (post) {
return post.id === id;
});
});
})]);
}
// return empty response
return Promise.all([topic, []]);
})
// dispatch success action
.then(function (results) {
var topic = results[0];
var lastThreeRelatedPosts = results[1];
var action = {
type: _actionTypes["default"].featureTopic.read.success,
payload: {
topic: topic,
lastThreeRelatedPosts: lastThreeRelatedPosts
}
};
dispatch(action);
return Promise.resolve(action);
})
// handle axios error response
["catch"](function (error) {
var failAction = _errorActionCreators["default"].axios(error, _actionTypes["default"].featureTopic.read.failure);
dispatch(failAction);
return Promise.reject(failAction);
});
};
}