Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@twreporter/redux

Package Overview
Dependencies
Maintainers
4
Versions
183
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@twreporter/redux - npm Package Compare versions

Comparing version 4.0.0 to 4.0.1

3

CHANGELOG.md
### Unrelease
### 4.0.1
- Enable pagination on posts action and reducer
### 4.0.0

@@ -3,0 +6,0 @@ - Move bookmark feature to @twreporter/registration

@@ -192,6 +192,23 @@ 'use strict';

});
it('Items of page are already fetched', function () {
var mockArgs = ['mock_target_uuid', 'categories', 10, 1];
var store = mockStore({
lists: {
mock_target_uuid: {
total: 10,
items: [post1, post2, post3, post4],
pages: {
1: [0, 3]
}
}
}
});
store.dispatch(actions.fetchListedPosts.apply(actions, mockArgs));
expect(store.getActions().length).to.equal(0);
return expect(store.dispatch(actions.fetchListedPosts.apply(actions, mockArgs))).eventually.equal(undefined);
});
});
context('It loads posts successfully', function () {
it('Should dispatch types.START_TO_GET_POSTS and types.GET_LISTED_POSTS', function () {
var mockArgs = ['mock_target_uuid', 'categories', 1];
it('Should load items when there is no items in the store', function () {
var mockArgs = ['mock_target_uuid', 'categories', 1, 0];
var store = mockStore({

@@ -233,3 +250,4 @@ lists: {}

total: 2,
listID: 'mock_target_uuid'
listID: 'mock_target_uuid',
page: 0
}

@@ -245,2 +263,52 @@ };

});
it('Should load items when page is provided', function () {
var mockArgs = ['mock_target_uuid', 'categories', 1, 2];
var store = mockStore({
lists: {}
});
var mockUrl = (0, _formApiUrl2.default)('posts?where={"categories":{"in":["mock_target_uuid"]}}&limit=1&offset=1');
var indexOfSlash = mockUrl.indexOf('/', 7);
var mockHost = mockUrl.slice(0, indexOfSlash);
var mockPath = mockUrl.slice(indexOfSlash);
var mockApiResponse = {
records: [{
_id: 'mock_category_article_id_01',
title: 'mock_category_article_title',
slug: 'mock-category-article-slug',
style: 'article',
og_description: 'mock_category_article_title_og_description'
}],
meta: {
limit: 1,
total: 2,
offset: 0
}
};
var expectedRequestAction = {
type: _actionTypes2.default.START_TO_GET_POSTS,
url: mockUrl
};
var expectedSuccessAction = {
type: _actionTypes2.default.GET_LISTED_POSTS,
payload: {
items: [{
_id: 'mock_category_article_id_01',
title: 'mock_category_article_title',
slug: 'mock-category-article-slug',
style: 'article',
og_description: 'mock_category_article_title_og_description'
}],
total: 2,
listID: 'mock_target_uuid',
page: 2
}
};
(0, _nock2.default)(mockHost).get(mockPath).reply(200, mockApiResponse);
return store.dispatch(actions.fetchListedPosts.apply(actions, mockArgs)).then(function () {
expect(store.getActions().length).to.equal(2);
expect(store.getActions()[0]).to.deep.equal(expectedRequestAction);
expect(store.getActions()[1].type).to.equal(expectedSuccessAction.type);
expect(store.getActions()[1].payload).to.deep.equal(expectedSuccessAction.payload);
});
});
});

@@ -247,0 +315,0 @@ context('If the api returns a failure', function () {

10

lib/actions/posts.js

@@ -128,2 +128,3 @@ 'use strict';

var limit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10;
var page = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;

@@ -138,2 +139,6 @@ return function (dispatch, getState) {

if (page > 0 && Array.isArray(_.get(list, ['pages', page]))) {
return Promise.resolve();
}
var where = _defineProperty({}, listType, {

@@ -143,6 +148,7 @@ in: [listID]

var offset = _.get(list, 'items.length', 0);
var offset = page > 0 ? (page - 1) * limit : _.get(list, 'items.length', 0);
var path = _apiEndpoints2.default.posts + '?where=' + JSON.stringify(where) + '&limit=' + limit + '&offset=' + offset;
return _fetchPosts(dispatch, path, _actionTypes2.default.GET_LISTED_POSTS, _actionTypes2.default.ERROR_TO_GET_LISTED_POSTS, { listID: listID });
return _fetchPosts(dispatch, path, _actionTypes2.default.GET_LISTED_POSTS, _actionTypes2.default.ERROR_TO_GET_LISTED_POSTS, { listID: listID, page: page });
};

@@ -149,0 +155,0 @@ }

@@ -88,3 +88,4 @@ 'use strict';

total: 10,
listID: 'mock-list-id'
listID: 'mock-list-id',
page: 0
}

@@ -95,5 +96,25 @@ })).to.deep.equal({

total: 10,
error: null
error: null,
pages: {}
}
});
(0, _chai.expect)((0, _posts.posts)({}, {
type: _actionTypes2.default.GET_LISTED_POSTS,
payload: {
items: [post1, post2, post3, post4],
total: 10,
listID: 'mock-list-id',
page: 2
}
})).to.deep.equal({
'mock-list-id': {
items: [post1.slug, post2.slug, post3.slug, post4.slug],
total: 10,
error: null,
pages: {
2: [0, 3]
}
}
});
});

@@ -100,0 +121,0 @@

@@ -83,3 +83,5 @@ 'use strict';

var listID = _.get(action, 'payload.listID', '');
var page = _.get(action, 'payload.page', 0);
var list = _.get(state, listID, {
pages: {},
items: [],

@@ -90,2 +92,4 @@ total: 0,

var itemsNum = list.items.length || 0;
list.items = _.concat(list.items, _.map(items, function (item) {

@@ -97,2 +101,6 @@ return item.slug;

if (page > 0) {
_.set(list.pages, page, [itemsNum, itemsNum + (items.length - 1)]);
}
return _.merge({}, state, _defineProperty({}, listID, list));

@@ -99,0 +107,0 @@ }

{
"name": "@twreporter/redux",
"version": "4.0.0",
"version": "4.0.1",
"description": "redux actions and reducers for twreporter website",

@@ -13,2 +13,3 @@ "main": "lib/index.js",

"lint": "eslint -c .eslintrc src ",
"lint-fix": "eslint -c .eslintrc src --fix",
"validate": "npm ls",

@@ -15,0 +16,0 @@ "dev": "npm run build:cus && gulp watch"

@@ -7,2 +7,49 @@ [![Tag](https://img.shields.io/github/tag/twreporter/twreporter-redux.svg)](https://github.com/twreporter/twreporter-redux/tags)

## Development
```
CUSTOMER_FOLDER=../entry_project/ npm run dev
// Assume your entry project is located at /home/nickli/entry_project.
// In the entry_project, you install @twreporter/redux,
// all the @twreporter/redux codes will be at /home/nickli/entry_project/@twreporter/redux.
// npm run dev will copy @twreporter/redux transpiled es5 javascript codes to your custom folder, that is entry_project.
```
## Build
`npm run build`
## Publish
`npm publish`
## actions
### index-page
Fetch all posts and topics [index page](https://www.twreporter.org) needed.
### posts
* Fetch a full post, which will include details, other than metadata, like what topic it belongs to,
or what other posts it is releated to.
* Fetch a list of posts, which will only include the metadata(like slug, title, description, published data ...etc) of posts.
### topics
* Fetch a full topic, which will include all the posts belonging to it.
* Fetch a list of topics, which will only include the metadata(like slug, title, description, published data ...etc) of topics.
## reducers
### index-page
`reduxState.indexPage` will contain each sections(like editor_picks, review, latest ...etc) in the [homepage of twreporter](https://www.twreporter.org)
### posts
`reduxState.post` will store `slug`, `error` and `isFetching`
`reduxState.posts` will store `items`, `error`and `total`
### topics
`reduxState.topic` will store `slug`, `error` and `isFetching`
`reduxState.topics` will store `items`, `totalPages`, `page`, `nPerPage`, `error` and `isFetching`
### entities
`reduxState.entities.posts` will store ${POST_SLUG}: ${POST_DATA} (string: Object) pair in a map
`reduxState.entities.topics` will store ${TOPIC_SLUG}: ${TOPIC_DATA} {string: Object} pair in a map

@@ -192,5 +192,28 @@ /* global describe, context, it, afterEach */

})
it('Items of page are already fetched', () => {
const mockArgs = [
'mock_target_uuid', // listID
'categories', // type
10, // limit
1, // page
]
const store = mockStore({
lists: {
mock_target_uuid: {
total: 10,
items: [post1, post2, post3, post4],
pages: {
// page 1 already fetched, and items post1, post2, post3 and post4
1: [0, 3],
},
},
},
})
store.dispatch(actions.fetchListedPosts(...mockArgs))
expect(store.getActions().length).to.equal(0) // no action is dispatched
return expect(store.dispatch(actions.fetchListedPosts(...mockArgs))).eventually.equal(undefined)
})
})
context('It loads posts successfully', () => {
it('Should dispatch types.START_TO_GET_POSTS and types.GET_LISTED_POSTS', () => {
it('Should load items when there is no items in the store', () => {
const mockArgs = [

@@ -200,2 +223,3 @@ 'mock_target_uuid', // listID

1, // limit
0, // page
]

@@ -243,2 +267,3 @@ const store = mockStore({

listID: 'mock_target_uuid',
page: 0,
},

@@ -257,2 +282,64 @@ }

})
it('Should load items when page is provided', () => {
const mockArgs = [
'mock_target_uuid', // listID
'categories', // type
1, // limit
2, // page
]
const store = mockStore({
// empty lists
lists: {
},
})
const mockUrl = formatUrl('posts?where={"categories":{"in":["mock_target_uuid"]}}&limit=1&offset=1')
const indexOfSlash = mockUrl.indexOf('/', 7)
const mockHost = mockUrl.slice(0, indexOfSlash) // example: 'http://localhost:8080'
const mockPath = mockUrl.slice(indexOfSlash) // example: '/posts?where=.....'
const mockApiResponse = {
records: [
{
_id: 'mock_category_article_id_01',
title: 'mock_category_article_title',
slug: 'mock-category-article-slug',
style: 'article',
og_description: 'mock_category_article_title_og_description',
},
],
meta: {
limit: 1,
total: 2,
offset: 0,
},
}
const expectedRequestAction = {
type: types.START_TO_GET_POSTS,
url: mockUrl,
}
const expectedSuccessAction = {
type: types.GET_LISTED_POSTS,
payload: {
items: [{
_id: 'mock_category_article_id_01',
title: 'mock_category_article_title',
slug: 'mock-category-article-slug',
style: 'article',
og_description: 'mock_category_article_title_og_description',
}],
total: 2,
listID: 'mock_target_uuid',
page: 2,
},
}
nock(mockHost)
.get(mockPath)
.reply(200, mockApiResponse)
return store.dispatch(actions.fetchListedPosts(...mockArgs))
.then(() => {
expect(store.getActions().length).to.equal(2) // 2 actions: REQUEST && SUCCESS
expect(store.getActions()[0]).to.deep.equal(expectedRequestAction)
expect(store.getActions()[1].type).to.equal(expectedSuccessAction.type)
expect(store.getActions()[1].payload).to.deep.equal(expectedSuccessAction.payload)
})
})
})

@@ -259,0 +346,0 @@ context('If the api returns a failure', () => {

@@ -106,3 +106,3 @@ import apiConfig from '../conf/api-config.json'

*/
export function fetchListedPosts(listID, listType, limit = 10) {
export function fetchListedPosts(listID, listType, limit = 10, page = 0) {
return (dispatch, getState) => {

@@ -117,2 +117,7 @@ const state = getState()

// items of page are already fetched
if (page > 0 && Array.isArray(_.get(list, ['pages', page]))) {
return Promise.resolve()
}
const where = {

@@ -124,6 +129,10 @@ [listType]: {

const offset = _.get(list, 'items.length', 0)
// if page provided(should bigger than 0),
// use page to count offset,
// otherwise, use current length of items
const offset = page > 0 ? (page - 1) * limit : _.get(list, 'items.length', 0)
const path = `${apiEndpoints.posts}?where=${JSON.stringify(where)}&limit=${limit}&offset=${offset}`
return _fetchPosts(dispatch, path, types.GET_LISTED_POSTS, types.ERROR_TO_GET_LISTED_POSTS, { listID })
return _fetchPosts(dispatch, path, types.GET_LISTED_POSTS, types.ERROR_TO_GET_LISTED_POSTS, { listID, page })
}

@@ -130,0 +139,0 @@ }

@@ -96,2 +96,3 @@ /* global describe, it */

listID: 'mock-list-id',
page: 0,
},

@@ -104,4 +105,28 @@ }),

error: null,
pages: {},
},
})
// page is provided
expect(
posts({
}, {
type: types.GET_LISTED_POSTS,
payload: {
items: [post1, post2, post3, post4],
total: 10,
listID: 'mock-list-id',
page: 2,
},
}),
).to.deep.equal({
'mock-list-id': {
items: [post1.slug, post2.slug, post3.slug, post4.slug],
total: 10,
error: null,
pages: {
2: [0, 3],
},
},
})
})

@@ -108,0 +133,0 @@

@@ -49,3 +49,12 @@ import types from '../constants/action-types'

const listID = _.get(action, 'payload.listID', '')
const page = _.get(action, 'payload.page', 0)
const list = _.get(state, listID, {
// pages is used to store items position,
// say, if
// pages = {
// 1: [0, 9]
// }
// which means, items of page 1 are stored
// from items[0] to items[9]
pages: {},
items: [],

@@ -56,2 +65,4 @@ total: 0,

const itemsNum = list.items.length || 0
list.items = _.concat(list.items, _.map(items, item => item.slug))

@@ -61,2 +72,8 @@ list.total = total

// not support page = 0
// page starts from 1, not 0
if (page > 0) {
_.set(list.pages, page, [itemsNum, (itemsNum + (items.length - 1))])
}
return _.merge({}, state, {

@@ -63,0 +80,0 @@ [listID]: list,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc