diff --git a/web/app/components/thread/thread.getters.test.js b/web/app/components/thread/thread.getters.test.js new file mode 100644 index 00000000..e8fc6791 --- /dev/null +++ b/web/app/components/thread/thread.getters.test.js @@ -0,0 +1,31 @@ +import store from 'common/store'; +import { getThreadIsCollapsed } from './thread.getters'; + +describe('collapsedThreads', () => { + const notScoredComment = { id: 1 }; + const goodComment = { id: 1, score: 3 }; + const badComment = { id: 1, score: -1 }; + + it('takes value from the state', () => { + const state = { collapsedThreads: { [notScoredComment.id]: true } }; + const collapsed = getThreadIsCollapsed(state, notScoredComment); + expect(collapsed).toEqual(true); + }); + + beforeAll(() => { + const config = { critical_score: 2 }; + store.set('config', config); + }); + + it('returns true when score is less then critical_score', () => { + const state = { collapsedThreads: {} }; + const collapsed = getThreadIsCollapsed(state, badComment); + expect(collapsed).toEqual(true); + }); + + it('returns true when score is less then critical_score', () => { + const state = { collapsedThreads: {} }; + const collapsed = getThreadIsCollapsed(state, goodComment); + expect(collapsed).toEqual(false); + }); +}); diff --git a/web/app/components/thread/thread.reducers.test.js b/web/app/components/thread/thread.reducers.test.js index f48e8931..954feaee 100644 --- a/web/app/components/thread/thread.reducers.test.js +++ b/web/app/components/thread/thread.reducers.test.js @@ -1,29 +1,18 @@ import { setCollapse } from './thread.actions'; import { collapsedThreads } from './thread.reducers'; -import { getThreadIsCollapsed } from './thread.getters'; describe('collapsedThreads', () => { const comment = { id: 1 }; it('should set collapsed to true', () => { - const collapsed = true; - const action = setCollapse(comment, collapsed); - - const newState = { - collapsedThreads: collapsedThreads({}, action), - }; - - expect(getThreadIsCollapsed(newState, comment)).toEqual(collapsed); + const action = setCollapse(comment, true); + const newState = collapsedThreads({}, action); + expect(newState).toEqual({ [comment.id]: true }); }); it('should set collapsed to false', () => { - const collapsed = false; - const action = setCollapse(comment, collapsed); - - const newState = { - collapsedThreads: collapsedThreads({}, action), - }; - - expect(getThreadIsCollapsed(newState, comment)).toEqual(collapsed); + const action = setCollapse(comment, false); + const newState = collapsedThreads({}, action); + expect(newState).toEqual({ [comment.id]: false }); }); }); diff --git a/web/app/components/user-info/index.js b/web/app/components/user-info/index.js index ee5e4016..d58b6c8c 100644 --- a/web/app/components/user-info/index.js +++ b/web/app/components/user-info/index.js @@ -1,3 +1,7 @@ +import { userComments, isLoadingUserComments } from './user-info.reducers'; + +export const userInfoReducers = { userComments, isLoadingUserComments }; + export { default } from './user-info'; require('./user-info.scss'); diff --git a/web/app/components/user-info/user-info.actions.js b/web/app/components/user-info/user-info.actions.js new file mode 100644 index 00000000..403ca402 --- /dev/null +++ b/web/app/components/user-info/user-info.actions.js @@ -0,0 +1,12 @@ +export const USER_INFO_FETCH_COMMENTS = 'USER_INFO/FETCH_COMMENTS'; +export const fetchComments = userId => ({ + type: USER_INFO_FETCH_COMMENTS, + userId, +}); + +export const USER_INFO_COMPLETE_FETCH_COMMENTS = 'USER_INFO/COMPLETE_FETCH_COMMENTS'; +export const completeFetchComments = (userId, comments) => ({ + type: USER_INFO_COMPLETE_FETCH_COMMENTS, + userId, + comments, +}); diff --git a/web/app/components/user-info/user-info.getters.js b/web/app/components/user-info/user-info.getters.js new file mode 100644 index 00000000..c5067547 --- /dev/null +++ b/web/app/components/user-info/user-info.getters.js @@ -0,0 +1,2 @@ +export const getUserComments = (state, userId) => state.userComments[userId] || null; +export const getIsLoadingUserComments = (state, userId) => state.isLoadingUserComments[userId] || false; diff --git a/web/app/components/user-info/user-info.getters.test.js b/web/app/components/user-info/user-info.getters.test.js new file mode 100644 index 00000000..c59118ac --- /dev/null +++ b/web/app/components/user-info/user-info.getters.test.js @@ -0,0 +1,40 @@ +import { getUserComments, getIsLoadingUserComments } from './user-info.getters'; + +describe('getUserComments', () => { + const userId = 1; + const comments = [{ id: 1 }]; + + it('returns null when comments have not been loaded', () => { + const state = { userComments: {} }; + const userComments = getUserComments(state, userId); + expect(userComments).toEqual(null); + }); + + it('returns comments when comments have been loaded', () => { + const state = { userComments: { [userId]: comments } }; + const userComments = getUserComments(state, userId); + expect(userComments).toEqual(comments); + }); +}); + +describe('getIsLoadingUserComments', () => { + const userId = 1; + + it('returns false when state is empty', () => { + const state = { isLoadingUserComments: {} }; + const loading = getIsLoadingUserComments(state, userId); + expect(loading).toEqual(false); + }); + + it('returns false when comments are not loading', () => { + const state = { isLoadingUserComments: { [userId]: false } }; + const loading = getIsLoadingUserComments(state, userId); + expect(loading).toEqual(false); + }); + + it('returns true when comments are loading', () => { + const state = { isLoadingUserComments: { [userId]: true } }; + const loading = getIsLoadingUserComments(state, userId); + expect(loading).toEqual(true); + }); +}); diff --git a/web/app/components/user-info/user-info.jsx b/web/app/components/user-info/user-info.jsx index d31833ec..155f8863 100644 --- a/web/app/components/user-info/user-info.jsx +++ b/web/app/components/user-info/user-info.jsx @@ -1,29 +1,31 @@ /** @jsx h */ import { h, Component } from 'preact'; +import { connect } from 'preact-redux'; import api from 'common/api'; import LastCommentsList from './last-comments-list'; import Avatar from 'components/avatar-icon'; +import { fetchComments, completeFetchComments } from './user-info.actions'; +import { getUserComments, getIsLoadingUserComments } from './user-info.getters'; class UserInfo extends Component { - constructor(props) { - super(props); - - this.state = { - comments: [], - isLoading: true, - }; - } - componentWillMount() { const { user: { id }, + comments, + isLoading, + fetchComments, + completeFetchComments, } = this.props; - api - .getUserComments({ user: id, limit: 10 }) - .then(({ comments = [] }) => this.setState({ comments })) - .finally(() => this.setState({ isLoading: false })); + if (!comments && !isLoading) { + fetchComments(id); + + api + .getUserComments({ user: id, limit: 10 }) + .then(({ comments }) => completeFetchComments(id, comments)) + .catch(() => completeFetchComments(id, [])); + } document.addEventListener('keydown', this.globalOnKeyDown); } @@ -40,9 +42,12 @@ class UserInfo extends Component { } } - render(props, { comments, isLoading }) { + render(props) { const { user: { name, id, isDefaultPicture, picture }, + comments = [], + isLoading, + onClose, } = props; return ( @@ -51,10 +56,20 @@ class UserInfo extends Component {
Last comments by {name}
{id}
-