Progress on chat conversation search, scrolling

This commit is contained in:
mgabdev 2020-12-22 13:38:52 -05:00
parent 15df66b234
commit 7a62adea3e
13 changed files with 96 additions and 50 deletions

View File

@ -7,7 +7,7 @@ class Api::V1::ChatConversationAccountsController < Api::BaseController
before_action :require_user!
before_action :set_account, only: [:block_messenger, :unblock_messenger, :messenger_block_relationships]
before_action :check_account_suspension, only: [:block_messenger, :unblock_messenger, :messenger_block_relationships]
before_action :set_chat_conversation, except: [:block_messenger, :unblock_messenger, :messenger_block_relationships]
before_action :set_chat_conversation, except: [:block_messenger, :unblock_messenger, :messenger_block_relationships, :search]
def block_messenger
@block = BlockChatMessengerService.new.call(current_user.account, @account)
@ -42,6 +42,13 @@ class Api::V1::ChatConversationAccountsController < Api::BaseController
render json: @chat_conversation_account, serializer: REST::ChatConversationAccountSerializer
end
def search
# : todo :
search_conversations = [] #ChatConversationAccount.where(account: current_account, is_hidden: false, is_approved: true).map(&:participant_account_ids)
# .joins(:account).where("accounts.display_name ILIKE ?", "%#{params[:q]}%")
render json: search_conversations, each_serializer: REST::ChatConversationAccountSerializer
end
private
def set_account

View File

@ -34,13 +34,8 @@ class Api::V1::ChatConversationController < Api::BaseController
end
def mark_chat_conversation_approved
approved_conversation_count = ChatConversationAccount.where(account: @account, is_hidden: false, is_approved: true).count
if approved_conversation_count >= ChatConversationAccount::PER_ACCOUNT_APPROVED_LIMIT
render json: { error: true, message: "You have #{approved_conversation_count} active chat conversations. The limit is #{ChatConversationAccount::PER_ACCOUNT_APPROVED_LIMIT}. Delete some conversations first before approving any more requests." }
else
@chat_conversation_account.update!(is_approved: true)
render json: @chat_conversation_account, serializer: REST::ChatConversationAccountSerializer
end
@chat_conversation_account.update!(is_approved: true)
render json: @chat_conversation_account, serializer: REST::ChatConversationAccountSerializer
end
def set_expiration_policy

View File

@ -509,40 +509,29 @@ export const setChatConversationExpirationFail = (error) => ({
error,
})
/**
*
*/
export const fetchChatConversationAccountSuggestions = (query) => (dispatch, getState) => {
export const searchApprovedChatConversations = (query) => (dispatch, getState) => {
if (!query) return
debouncedFetchChatConversationAccountSuggestions(query, dispatch, getState)
debouncedSearchApprovedChatConversations(query, dispatch, getState)
}
export const debouncedFetchChatConversationAccountSuggestions = debounce((query, dispatch, getState) => {
export const debouncedSearchApprovedChatConversations = debounce((query, dispatch, getState) => {
if (!query) return
api(getState).get('/api/v1/accounts/search', {
params: {
q: query,
resolve: false,
limit: 4,
},
api(getState).get('/api/v1/chat_conversation_accounts/_/search', {
params: { q: query },
}).then((response) => {
// const next = getLinks(response).refs.find(link => link.rel === 'next')
// const conversationsAccounts = [].concat.apply([], response.data.map((c) => c.other_accounts))
dispatch(importFetchedAccounts(response.data))
// dispatch(importFetchedAccounts(conversationsAccounts))
// dispatch(importFetchedChatMessages(conversationsChatMessages))
// dispatch(fetchChatConversationsSuccess(response.data, next ? next.uri : null))
dispatch(fetchChatConversationAccountSuggestionsSuccess(response.data))
const conversationsAccounts = [].concat.apply([], response.data.map((c) => c.other_accounts))
dispatch(searchApprovedChatConversationsSuccess(response.data))
}).catch((error) => {
//
})
}, 650, { leading: true })
const fetchChatConversationAccountSuggestionsSuccess = (chatConversations) => ({
const searchApprovedChatConversationsSuccess = (chatConversations) => ({
type: CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS,
chatConversations,
})

View File

@ -9,6 +9,8 @@ export const CLEAR_CHAT_CONVERSATION_CREATE_SEARCH_ACCOUNTS = 'CLEAR_CHAT_CONVER
export const SET_CHAT_CONVERSATION_SELECTED = 'SET_CHAT_CONVERSATION_SELECTED'
export const SET_CHAT_CONVERSATION_SEARCH_VALUE = 'SET_CHAT_CONVERSATION_SEARCH_VALUE'
/**
*
*/
@ -55,3 +57,13 @@ export const setChatConversationSelected = (chatConversationId) => (dispatch) =>
chatConversationId,
})
}
/**
*
*/
export const onChangeSearch = (value) => (dispatch) => {
dispatch({
type: SET_CHAT_CONVERSATION_SEARCH_VALUE,
value,
})
}

View File

@ -62,11 +62,25 @@ class ChatConversationsList extends ImmutablePureComponent {
}
const mapStateToProps = (state, { source }) => ({
chatConversationIds: state.getIn(['chat_conversation_lists', source, 'items']),
hasMore: !!state.getIn(['chat_conversation_lists', source, 'next']),
isLoading: state.getIn(['chat_conversation_lists', source, 'isLoading']),
})
const mapStateToProps = (state, { source }) => {
let chatConversationIds
if (source === 'approved') {
const chatSearchValue = state.getIn(['chats', 'searchValue'], '')
if (!!chatSearchValue && chatSearchValue.length > 0) {
chatConversationIds = state.getIn(['chat_conversation_lists', 'approved_search', 'items'])
} else {
chatConversationIds = state.getIn(['chat_conversation_lists', source, 'items'])
}
} else {
chatConversationIds = state.getIn(['chat_conversation_lists', source, 'items'])
}
return {
chatConversationIds,
hasMore: !!state.getIn(['chat_conversation_lists', source, 'next']),
isLoading: state.getIn(['chat_conversation_lists', source, 'isLoading']),
}
}
const mapDispatchToProps = (dispatch) => ({
onFetchChatConversations(source) {

View File

@ -1,21 +1,18 @@
import React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { searchApprovedChatConversations } from '../../../actions/chat_conversations'
import { onChangeSearch } from '../../../actions/chats'
import Input from '../../../components/input'
class ChatConversationsSearch extends React.PureComponent {
state = {
value: '',
}
handleOnChange = (value) => {
this.setState({ value })
this.props.onChange(value)
}
render() {
const { value } = this.state
const { value } = this.props
return (
<div className={[_s.d, _s.h60PX, _s.w100PC, _s.px10, _s.py10, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
@ -33,10 +30,20 @@ class ChatConversationsSearch extends React.PureComponent {
}
const mapStateToProps = (state) => ({
value: state.getIn(['chats', 'searchValue'], ''),
})
const mapDispatchToProps = (dispatch) => ({
onChange(value) {
// dispatch()
dispatch(onChangeSearch(value))
dispatch(searchApprovedChatConversations(value))
}
})
export default connect(null, mapDispatchToProps)(ChatConversationsSearch)
ChatConversationsSearch.propTypes = {
value: PropTypes.string,
onChange: PropTypes.func.isRequired,
}
export default connect(mapStateToProps, mapDispatchToProps)(ChatConversationsSearch)

View File

@ -45,10 +45,12 @@ class ChatMessagesComposeForm extends React.PureComponent {
}
onBlur = () => {
console.log("onBlur")
this.setState({ focused: false })
}
onFocus = () => {
console.log("onFocus")
this.setState({ focused: true })
}

View File

@ -67,8 +67,8 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
if (prevProps.chatMessageIds.size === 0 && this.props.chatMessageIds.size > 0 && this.scrollContainerRef) {
this.scrollToBottom()
this.props.onReadChatConversation(this.props.chatConversationId)
} else if (prevProps.chatMessageIds.size < this.props.chatMessageIds.size && this.scrollContainerRef) {
// this.setScrollTop(this.scrollContainerRef.scrollHeight)
} else if (this.props.chatMessageIds.size - prevProps.chatMessageIds.size === 1) {
this.scrollToBottom()
}
}
@ -121,7 +121,7 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
scrollToBottom = () => {
if (this.messagesEnd) {
this.messagesEnd.scrollIntoView({ behavior: 'smooth' });
this.messagesEnd.scrollIntoView()
}
}
@ -225,6 +225,11 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
this.containerNode = c
}
setMessagesEnd = (c) => {
this.messagesEnd = c
this.scrollToBottom()
}
setScrollContainerRef = (c) => {
this.scrollContainerRef = c
@ -242,7 +247,6 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
isPartial,
hasMore,
amITalkingToMyself,
onScrollToBottom,
onScroll,
isXS,
} = this.props
@ -338,11 +342,13 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
</IntersectionObserverArticle>
))
}
<div
style={{ float: 'left', clear: 'both' }}
ref={(el) => { this.messagesEnd = el }}
/>
</div>
<div
key='end-message'
style={{ float: 'left', clear: 'both' }}
ref={this.setMessagesEnd}
/>
</div>
</div>
)

View File

@ -23,6 +23,7 @@ import {
CHAT_CONVERSATIONS_MUTED_EXPAND_SUCCESS,
CHAT_CONVERSATIONS_MUTED_EXPAND_FAIL,
CHAT_CONVERSATIONS_CREATE_SUCCESS,
CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS,
} from '../actions/chat_conversations'
const initialState = ImmutableMap({
@ -41,6 +42,9 @@ const initialState = ImmutableMap({
isLoading: false,
items: ImmutableList(),
}),
approved_search: ImmutableMap({
items: ImmutableList(),
}),
})
const normalizeList = (state, source, chatConversations, next) => {
@ -107,6 +111,9 @@ export default function chat_conversation_lists(state = initialState, action) {
case CHAT_CONVERSATIONS_CREATE_SUCCESS:
return appendToList(state, 'approved', [action.chatConversation], action.next)
case CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS:
return normalizeList(state, 'approved_search', action.chatConversations, null)
default:
return state
}

View File

@ -18,6 +18,7 @@ import {
CHAT_CONVERSATION_REQUEST_APPROVE_SUCCESS,
CHAT_CONVERSATION_MARK_READ_SUCCESS,
SET_CHAT_CONVERSATION_EXPIRATION_SUCCESS,
CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS,
} from '../actions/chat_conversations'
const initialState = ImmutableMap()
@ -50,6 +51,7 @@ export default function chat_conversations(state = initialState, action) {
case CHAT_CONVERSATIONS_APPROVED_EXPAND_SUCCESS:
case CHAT_CONVERSATIONS_REQUESTED_FETCH_SUCCESS:
case CHAT_CONVERSATIONS_REQUESTED_EXPAND_SUCCESS:
case CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS:
return importChatConversations(state, action.chatConversations)
case CHAT_MESSAGES_SEND_SUCCESS:
return setLastChatMessage(state, action.chatMessage)

View File

@ -8,6 +8,7 @@ import {
CHAT_CONVERSATION_CREATE_SEARCH_ACCOUNTS_SUCCESS,
CLEAR_CHAT_CONVERSATION_CREATE_SEARCH_ACCOUNTS,
SET_CHAT_CONVERSATION_SELECTED,
SET_CHAT_CONVERSATION_SEARCH_VALUE,
} from '../actions/chats'
import {
CHAT_CONVERSATION_APPROVED_UNREAD_COUNT_FETCH_SUCCESS,
@ -24,6 +25,7 @@ const initialState = ImmutableMap({
selectedChatConversationId: null,
chatConversationRequestCount: 0,
chatsUnreadCount: 0,
searchValue: '',
})
export default function chats(state = initialState, action) {
@ -42,6 +44,8 @@ export default function chats(state = initialState, action) {
const chatConversationUnreadCount = action.chatConversation.get('unread_count')
const totalUnreadCount = state.get('chatsUnreadCount')
return state.set('chatsUnreadCount', Math.max(totalUnreadCount - chatConversationUnreadCount, 0))
case SET_CHAT_CONVERSATION_SEARCH_VALUE:
return state.set('searchValue', action.value)
default:
return state
}

View File

@ -237,6 +237,7 @@ Rails.application.routes.draw do
post :unblock_messenger
post :mute_chat_conversation
post :unmute_chat_conversation
get :search
end
end