Progress on chat conversation search, scrolling
This commit is contained in:
parent
15df66b234
commit
7a62adea3e
|
@ -7,7 +7,7 @@ class Api::V1::ChatConversationAccountsController < Api::BaseController
|
||||||
before_action :require_user!
|
before_action :require_user!
|
||||||
before_action :set_account, only: [:block_messenger, :unblock_messenger, :messenger_block_relationships]
|
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 :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
|
def block_messenger
|
||||||
@block = BlockChatMessengerService.new.call(current_user.account, @account)
|
@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
|
render json: @chat_conversation_account, serializer: REST::ChatConversationAccountSerializer
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def set_account
|
def set_account
|
||||||
|
|
|
@ -34,13 +34,8 @@ class Api::V1::ChatConversationController < Api::BaseController
|
||||||
end
|
end
|
||||||
|
|
||||||
def mark_chat_conversation_approved
|
def mark_chat_conversation_approved
|
||||||
approved_conversation_count = ChatConversationAccount.where(account: @account, is_hidden: false, is_approved: true).count
|
@chat_conversation_account.update!(is_approved: true)
|
||||||
if approved_conversation_count >= ChatConversationAccount::PER_ACCOUNT_APPROVED_LIMIT
|
render json: @chat_conversation_account, serializer: REST::ChatConversationAccountSerializer
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_expiration_policy
|
def set_expiration_policy
|
||||||
|
|
|
@ -509,40 +509,29 @@ export const setChatConversationExpirationFail = (error) => ({
|
||||||
error,
|
error,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const fetchChatConversationAccountSuggestions = (query) => (dispatch, getState) => {
|
export const searchApprovedChatConversations = (query) => (dispatch, getState) => {
|
||||||
if (!query) return
|
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
|
if (!query) return
|
||||||
|
|
||||||
api(getState).get('/api/v1/accounts/search', {
|
api(getState).get('/api/v1/chat_conversation_accounts/_/search', {
|
||||||
params: {
|
params: { q: query },
|
||||||
q: query,
|
|
||||||
resolve: false,
|
|
||||||
limit: 4,
|
|
||||||
},
|
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
// const next = getLinks(response).refs.find(link => link.rel === 'next')
|
const conversationsAccounts = [].concat.apply([], response.data.map((c) => c.other_accounts))
|
||||||
// const conversationsAccounts = [].concat.apply([], response.data.map((c) => c.other_accounts))
|
dispatch(searchApprovedChatConversationsSuccess(response.data))
|
||||||
|
|
||||||
dispatch(importFetchedAccounts(response.data))
|
|
||||||
|
|
||||||
// dispatch(importFetchedAccounts(conversationsAccounts))
|
|
||||||
// dispatch(importFetchedChatMessages(conversationsChatMessages))
|
|
||||||
// dispatch(fetchChatConversationsSuccess(response.data, next ? next.uri : null))
|
|
||||||
|
|
||||||
dispatch(fetchChatConversationAccountSuggestionsSuccess(response.data))
|
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
//
|
//
|
||||||
})
|
})
|
||||||
}, 650, { leading: true })
|
}, 650, { leading: true })
|
||||||
|
|
||||||
const fetchChatConversationAccountSuggestionsSuccess = (chatConversations) => ({
|
const searchApprovedChatConversationsSuccess = (chatConversations) => ({
|
||||||
type: CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS,
|
type: CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS,
|
||||||
chatConversations,
|
chatConversations,
|
||||||
})
|
})
|
|
@ -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_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,
|
chatConversationId,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export const onChangeSearch = (value) => (dispatch) => {
|
||||||
|
dispatch({
|
||||||
|
type: SET_CHAT_CONVERSATION_SEARCH_VALUE,
|
||||||
|
value,
|
||||||
|
})
|
||||||
|
}
|
|
@ -62,11 +62,25 @@ class ChatConversationsList extends ImmutablePureComponent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, { source }) => ({
|
const mapStateToProps = (state, { source }) => {
|
||||||
chatConversationIds: state.getIn(['chat_conversation_lists', source, 'items']),
|
let chatConversationIds
|
||||||
hasMore: !!state.getIn(['chat_conversation_lists', source, 'next']),
|
if (source === 'approved') {
|
||||||
isLoading: state.getIn(['chat_conversation_lists', source, 'isLoading']),
|
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) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
onFetchChatConversations(source) {
|
onFetchChatConversations(source) {
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
import { searchApprovedChatConversations } from '../../../actions/chat_conversations'
|
||||||
|
import { onChangeSearch } from '../../../actions/chats'
|
||||||
import Input from '../../../components/input'
|
import Input from '../../../components/input'
|
||||||
|
|
||||||
class ChatConversationsSearch extends React.PureComponent {
|
class ChatConversationsSearch extends React.PureComponent {
|
||||||
|
|
||||||
state = {
|
|
||||||
value: '',
|
|
||||||
}
|
|
||||||
|
|
||||||
handleOnChange = (value) => {
|
handleOnChange = (value) => {
|
||||||
this.setState({ value })
|
|
||||||
this.props.onChange(value)
|
this.props.onChange(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { value } = this.state
|
const { value } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={[_s.d, _s.h60PX, _s.w100PC, _s.px10, _s.py10, _s.borderBottom1PX, _s.borderColorSecondary].join(' ')}>
|
<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) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
onChange(value) {
|
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)
|
|
@ -45,10 +45,12 @@ class ChatMessagesComposeForm extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBlur = () => {
|
onBlur = () => {
|
||||||
|
console.log("onBlur")
|
||||||
this.setState({ focused: false })
|
this.setState({ focused: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
onFocus = () => {
|
onFocus = () => {
|
||||||
|
console.log("onFocus")
|
||||||
this.setState({ focused: true })
|
this.setState({ focused: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -67,8 +67,8 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
||||||
if (prevProps.chatMessageIds.size === 0 && this.props.chatMessageIds.size > 0 && this.scrollContainerRef) {
|
if (prevProps.chatMessageIds.size === 0 && this.props.chatMessageIds.size > 0 && this.scrollContainerRef) {
|
||||||
this.scrollToBottom()
|
this.scrollToBottom()
|
||||||
this.props.onReadChatConversation(this.props.chatConversationId)
|
this.props.onReadChatConversation(this.props.chatConversationId)
|
||||||
} else if (prevProps.chatMessageIds.size < this.props.chatMessageIds.size && this.scrollContainerRef) {
|
} else if (this.props.chatMessageIds.size - prevProps.chatMessageIds.size === 1) {
|
||||||
// this.setScrollTop(this.scrollContainerRef.scrollHeight)
|
this.scrollToBottom()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
||||||
|
|
||||||
scrollToBottom = () => {
|
scrollToBottom = () => {
|
||||||
if (this.messagesEnd) {
|
if (this.messagesEnd) {
|
||||||
this.messagesEnd.scrollIntoView({ behavior: 'smooth' });
|
this.messagesEnd.scrollIntoView()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,6 +225,11 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
||||||
this.containerNode = c
|
this.containerNode = c
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setMessagesEnd = (c) => {
|
||||||
|
this.messagesEnd = c
|
||||||
|
this.scrollToBottom()
|
||||||
|
}
|
||||||
|
|
||||||
setScrollContainerRef = (c) => {
|
setScrollContainerRef = (c) => {
|
||||||
this.scrollContainerRef = c
|
this.scrollContainerRef = c
|
||||||
|
|
||||||
|
@ -242,7 +247,6 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
||||||
isPartial,
|
isPartial,
|
||||||
hasMore,
|
hasMore,
|
||||||
amITalkingToMyself,
|
amITalkingToMyself,
|
||||||
onScrollToBottom,
|
|
||||||
onScroll,
|
onScroll,
|
||||||
isXS,
|
isXS,
|
||||||
} = this.props
|
} = this.props
|
||||||
|
@ -338,11 +342,13 @@ class ChatMessageScrollingList extends ImmutablePureComponent {
|
||||||
</IntersectionObserverArticle>
|
</IntersectionObserverArticle>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
<div
|
|
||||||
style={{ float: 'left', clear: 'both' }}
|
|
||||||
ref={(el) => { this.messagesEnd = el }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
key='end-message'
|
||||||
|
style={{ float: 'left', clear: 'both' }}
|
||||||
|
ref={this.setMessagesEnd}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
CHAT_CONVERSATIONS_MUTED_EXPAND_SUCCESS,
|
CHAT_CONVERSATIONS_MUTED_EXPAND_SUCCESS,
|
||||||
CHAT_CONVERSATIONS_MUTED_EXPAND_FAIL,
|
CHAT_CONVERSATIONS_MUTED_EXPAND_FAIL,
|
||||||
CHAT_CONVERSATIONS_CREATE_SUCCESS,
|
CHAT_CONVERSATIONS_CREATE_SUCCESS,
|
||||||
|
CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS,
|
||||||
} from '../actions/chat_conversations'
|
} from '../actions/chat_conversations'
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
const initialState = ImmutableMap({
|
||||||
|
@ -41,6 +42,9 @@ const initialState = ImmutableMap({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
items: ImmutableList(),
|
items: ImmutableList(),
|
||||||
}),
|
}),
|
||||||
|
approved_search: ImmutableMap({
|
||||||
|
items: ImmutableList(),
|
||||||
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
const normalizeList = (state, source, chatConversations, next) => {
|
const normalizeList = (state, source, chatConversations, next) => {
|
||||||
|
@ -107,6 +111,9 @@ export default function chat_conversation_lists(state = initialState, action) {
|
||||||
case CHAT_CONVERSATIONS_CREATE_SUCCESS:
|
case CHAT_CONVERSATIONS_CREATE_SUCCESS:
|
||||||
return appendToList(state, 'approved', [action.chatConversation], action.next)
|
return appendToList(state, 'approved', [action.chatConversation], action.next)
|
||||||
|
|
||||||
|
case CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS:
|
||||||
|
return normalizeList(state, 'approved_search', action.chatConversations, null)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import {
|
||||||
CHAT_CONVERSATION_REQUEST_APPROVE_SUCCESS,
|
CHAT_CONVERSATION_REQUEST_APPROVE_SUCCESS,
|
||||||
CHAT_CONVERSATION_MARK_READ_SUCCESS,
|
CHAT_CONVERSATION_MARK_READ_SUCCESS,
|
||||||
SET_CHAT_CONVERSATION_EXPIRATION_SUCCESS,
|
SET_CHAT_CONVERSATION_EXPIRATION_SUCCESS,
|
||||||
|
CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS,
|
||||||
} from '../actions/chat_conversations'
|
} from '../actions/chat_conversations'
|
||||||
|
|
||||||
const initialState = ImmutableMap()
|
const initialState = ImmutableMap()
|
||||||
|
@ -50,6 +51,7 @@ export default function chat_conversations(state = initialState, action) {
|
||||||
case CHAT_CONVERSATIONS_APPROVED_EXPAND_SUCCESS:
|
case CHAT_CONVERSATIONS_APPROVED_EXPAND_SUCCESS:
|
||||||
case CHAT_CONVERSATIONS_REQUESTED_FETCH_SUCCESS:
|
case CHAT_CONVERSATIONS_REQUESTED_FETCH_SUCCESS:
|
||||||
case CHAT_CONVERSATIONS_REQUESTED_EXPAND_SUCCESS:
|
case CHAT_CONVERSATIONS_REQUESTED_EXPAND_SUCCESS:
|
||||||
|
case CHAT_CONVERSATION_APPROVED_SEARCH_FETCH_SUCCESS:
|
||||||
return importChatConversations(state, action.chatConversations)
|
return importChatConversations(state, action.chatConversations)
|
||||||
case CHAT_MESSAGES_SEND_SUCCESS:
|
case CHAT_MESSAGES_SEND_SUCCESS:
|
||||||
return setLastChatMessage(state, action.chatMessage)
|
return setLastChatMessage(state, action.chatMessage)
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
CHAT_CONVERSATION_CREATE_SEARCH_ACCOUNTS_SUCCESS,
|
CHAT_CONVERSATION_CREATE_SEARCH_ACCOUNTS_SUCCESS,
|
||||||
CLEAR_CHAT_CONVERSATION_CREATE_SEARCH_ACCOUNTS,
|
CLEAR_CHAT_CONVERSATION_CREATE_SEARCH_ACCOUNTS,
|
||||||
SET_CHAT_CONVERSATION_SELECTED,
|
SET_CHAT_CONVERSATION_SELECTED,
|
||||||
|
SET_CHAT_CONVERSATION_SEARCH_VALUE,
|
||||||
} from '../actions/chats'
|
} from '../actions/chats'
|
||||||
import {
|
import {
|
||||||
CHAT_CONVERSATION_APPROVED_UNREAD_COUNT_FETCH_SUCCESS,
|
CHAT_CONVERSATION_APPROVED_UNREAD_COUNT_FETCH_SUCCESS,
|
||||||
|
@ -24,6 +25,7 @@ const initialState = ImmutableMap({
|
||||||
selectedChatConversationId: null,
|
selectedChatConversationId: null,
|
||||||
chatConversationRequestCount: 0,
|
chatConversationRequestCount: 0,
|
||||||
chatsUnreadCount: 0,
|
chatsUnreadCount: 0,
|
||||||
|
searchValue: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function chats(state = initialState, action) {
|
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 chatConversationUnreadCount = action.chatConversation.get('unread_count')
|
||||||
const totalUnreadCount = state.get('chatsUnreadCount')
|
const totalUnreadCount = state.get('chatsUnreadCount')
|
||||||
return state.set('chatsUnreadCount', Math.max(totalUnreadCount - chatConversationUnreadCount, 0))
|
return state.set('chatsUnreadCount', Math.max(totalUnreadCount - chatConversationUnreadCount, 0))
|
||||||
|
case SET_CHAT_CONVERSATION_SEARCH_VALUE:
|
||||||
|
return state.set('searchValue', action.value)
|
||||||
default:
|
default:
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
|
@ -237,6 +237,7 @@ Rails.application.routes.draw do
|
||||||
post :unblock_messenger
|
post :unblock_messenger
|
||||||
post :mute_chat_conversation
|
post :mute_chat_conversation
|
||||||
post :unmute_chat_conversation
|
post :unmute_chat_conversation
|
||||||
|
get :search
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue