diff --git a/src/actions/user-messages.js b/src/actions/user-messages.js index 0826f5f9..1e80e133 100644 --- a/src/actions/user-messages.js +++ b/src/actions/user-messages.js @@ -74,11 +74,12 @@ export function updateUserMessagesStatus(status) { }; } -export function loadMessageableUsers(users) { +export function loadMessageableUsers(users, meta = { offset: 0 }) { return { type: LOAD_MESSAGEABLE_USERS, payload: { users - } + }, + meta }; } diff --git a/src/api/client.js b/src/api/client.js index b84319cb..8aea2596 100644 --- a/src/api/client.js +++ b/src/api/client.js @@ -279,8 +279,8 @@ export default class ApiClient { return await response.json(); } - async mutualFollows(userId: UserId): Promise> { - const response = await this.get(`/api/v1/user/${userId}/mutual-follows`); + async mutualFollows(userId: UserId, query: Object = {}): Promise> { + const response = await this.get(`/api/v1/user/${userId}/mutual-follows`, query); return await response.json(); } diff --git a/src/api/controller.js b/src/api/controller.js index fdeb992f..2ed5866b 100644 --- a/src/api/controller.js +++ b/src/api/controller.js @@ -1927,6 +1927,8 @@ export default class ApiController { }); this.applySortQuery(qb, ctx.query, 'username'); + this.applyLimitQuery(qb, ctx.query); + this.applyOffsetQuery(qb, ctx.query); }) .fetch({ withRelated: USER_RELATIONS diff --git a/src/components/conversations/user-list.js b/src/components/conversations/user-list.js index 5ea03570..037c5d6d 100644 --- a/src/components/conversations/user-list.js +++ b/src/components/conversations/user-list.js @@ -18,9 +18,10 @@ import React from 'react'; import { Link } from 'react-router'; import Avatar from '../user/avatar'; +import { getName } from '../../utils/user'; -export default function UserList({ onClick, selectedUserId, users, user_messages }) { +export default function UserList({ canLoadMore, selectedUserId, users, user_messages, onClick, onLoadMore }) { const followedUsers = user_messages.get('messageableUserIds').map(id => users.get(id)); const userItems = followedUsers.map((user, index) => { @@ -40,7 +41,7 @@ export default function UserList({ onClick, selectedUserId, users, user_messages > - {user.get('username')} + {getName(user)} {numUnread > 0 &&
{numUnread}
} @@ -52,6 +53,9 @@ export default function UserList({ onClick, selectedUserId, users, user_messages return (
{userItems} + {canLoadMore && + + }
); } diff --git a/src/less/blocks/aux-nav.less b/src/less/blocks/aux-nav.less index 61e11087..d044a618 100644 --- a/src/less/blocks/aux-nav.less +++ b/src/less/blocks/aux-nav.less @@ -19,6 +19,8 @@ @active-icon: #6AB7EA; @active-text: #1078B4; + display: flex; + flex-direction: column; margin-bottom: @doubleSpace; &__item { @@ -64,4 +66,15 @@ font-size: 12px; margin-left: auto; } + + // TODO: I'm not sure if this should be here. + &__button { + margin: @space auto; + padding: 8px 50px; + border: none; + outline: none; + background-color: white; + box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1); + color: #1078B4; + } } diff --git a/src/pages/conversations.js b/src/pages/conversations.js index a6a87185..e516bb59 100644 --- a/src/pages/conversations.js +++ b/src/pages/conversations.js @@ -45,6 +45,8 @@ import RiverItemCreateForm from '../components/river/type/text/create-form'; import User from '../components/user'; +const USER_LIMIT = 5; + class ConversationsPage extends React.Component { static async fetchData(router, store, client) { const state = store.getState(); @@ -55,7 +57,7 @@ class ConversationsPage extends React.Component { } const triggers = new ActionsTrigger(client, store.dispatch); - const users = await triggers.loadMessageableUsers(currentUserId); + const users = await triggers.loadMessageableUsers(currentUserId, { offset: 0, limit: USER_LIMIT }); if (users.length > 0) { const firstUserId = users[0].id; @@ -118,6 +120,11 @@ class ConversationsPage extends React.Component { this.triggers.deleteUserMessage(message.get('receiver_id'), message.get('id')); }; + handleLoadMoreUsers = async () => { + const offset = this.props.user_messages.get('messageableUserIds').size; + await this.triggers.loadMessageableUsers(this.props.current_user.get('id'), { offset, limit: USER_LIMIT }); + } + setMessagesInterval = (selectedUserId) => { clearInterval(this.messageIntervalId); @@ -185,10 +192,12 @@ class ConversationsPage extends React.Component { diff --git a/src/store/user_messages.js b/src/store/user_messages.js index 53f563db..e267f994 100644 --- a/src/store/user_messages.js +++ b/src/store/user_messages.js @@ -24,7 +24,8 @@ import { userMessages } from '../actions'; export const initialState = i.fromJS({ numUnread: 0, byUser: {}, // userId => { numUnread: 0, messages: [] }, - messageableUserIds: [] // for optimization + messageableUserIds: [], // for optimization + canLoadMore: true, }); export function reducer(state = initialState, action) { @@ -85,7 +86,18 @@ export function reducer(state = initialState, action) { state = state.withMutations(state => { state.update('byUser', byUser => byUser.mergeDeep(i.fromJS(usersById))); - state.set('messageableUserIds', i.List(userIds)); + + if (action.meta.offset > 0) { + state.update('messageableUserIds', ids => { + return ids.slice(0, action.meta.offset).push(...userIds); + }); + } else { + state.set('messageableUserIds', i.List(userIds)); + } + + if (userIds.length < action.meta.limit) { + state.set('canLoadMore', false); + } }); break; diff --git a/src/triggers/index.js b/src/triggers/index.js index bad82347..4747d3e8 100644 --- a/src/triggers/index.js +++ b/src/triggers/index.js @@ -903,13 +903,12 @@ export class ActionsTrigger { } } - // TODO: Load more - loadMessageableUsers = async (currentUserId) => { + loadMessageableUsers = async (currentUserId, params = {}) => { let users; try { - users = await this.client.mutualFollows(currentUserId); - this.dispatch(a.userMessages.loadMessageableUsers(users)); + users = await this.client.mutualFollows(currentUserId, params); + this.dispatch(a.userMessages.loadMessageableUsers(users, params)); } catch (e) { this.dispatch(a.messages.addError(e.message)); }