Chats: add individual chat page for mobile

loading-indicator-on-tls^2
Alex Gleason 2020-08-27 22:46:48 -05:00
rodzic 4b22726016
commit 942b3fdebe
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
3 zmienionych plików z 115 dodań i 1 usunięć

Wyświetl plik

@ -0,0 +1,109 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import {
fetchChatMessages,
sendChatMessage,
markChatRead,
} from 'soapbox/actions/chats';
import { List as ImmutableList, OrderedSet as ImmutableOrderedSet } from 'immutable';
import ChatMessageList from './components/chat_message_list';
import Column from 'soapbox/features/ui/components/column';
const mapStateToProps = (state, { params }) => ({
me: state.get('me'),
chat: state.getIn(['chats', params.chatId]),
chatMessageIds: state.getIn(['chat_message_lists', params.chatId], ImmutableOrderedSet()),
});
export default @connect(mapStateToProps)
@injectIntl
class ChatWindow extends ImmutablePureComponent {
static propTypes = {
dispatch: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
chatMessageIds: ImmutablePropTypes.orderedSet,
chat: ImmutablePropTypes.map,
me: PropTypes.node,
}
static defaultProps = {
chatMessages: ImmutableList(),
}
state = {
content: '',
}
handleKeyDown = (chatId) => {
return (e) => {
if (e.key === 'Enter') {
this.props.dispatch(sendChatMessage(chatId, this.state));
this.setState({ content: '' });
e.preventDefault();
}
};
}
handleContentChange = (e) => {
this.setState({ content: e.target.value });
}
handleReadChat = (e) => {
const { dispatch, chat } = this.props;
dispatch(markChatRead(chat.get('id')));
}
focusInput = () => {
if (!this.inputElem) return;
this.inputElem.focus();
}
setInputRef = (el) => {
this.inputElem = el;
this.focusInput();
};
componentDidMount() {
const { dispatch, chatMessages, params } = this.props;
if (chatMessages && chatMessages.count() < 1)
dispatch(fetchChatMessages(params.chatId));
}
componentDidUpdate(prevProps) {
const markReadConditions = [
() => this.props.chat !== undefined,
() => document.activeElement === this.inputElem,
() => this.props.chat.get('unread') > 0,
];
if (markReadConditions.every(c => c() === true))
this.handleReadChat();
}
render() {
const { chatMessageIds, chat } = this.props;
if (!chat) return null;
return (
<Column>
<ChatMessageList chatMessageIds={chatMessageIds} />
<div className='pane__actions simple_form'>
<textarea
rows={1}
placeholder='Send a message...'
onKeyDown={this.handleKeyDown(chat.get('id'))}
onChange={this.handleContentChange}
value={this.state.content}
ref={this.setInputRef}
/>
</div>
</Column>
);
}
}

Wyświetl plik

@ -80,6 +80,7 @@ import {
SecurityForm,
MfaForm,
ChatIndex,
ChatRoom,
} from './util/async-components';
// Dummy import, to make sure that <Status /> ends up in the application bundle.
@ -239,7 +240,7 @@ class SwitchingColumnsArea extends React.PureComponent {
<WrappedRoute path='/search' publicRoute page={SearchPage} component={Search} content={children} />
<WrappedRoute path='/chats' exact layout={LAYOUT.DEFAULT} component={ChatIndex} content={children} />
{/* <WrappedRoute path='/chats/:chatId' layout={LAYOUT.DEFAULT} component={ChatRoom} content={children} /> */}
<WrappedRoute path='/chats/:chatId' layout={LAYOUT.DEFAULT} component={ChatRoom} content={children} />
<WrappedRoute path='/follow_requests' layout={LAYOUT.DEFAULT} component={FollowRequests} content={children} />
<WrappedRoute path='/blocks' layout={LAYOUT.DEFAULT} component={Blocks} content={children} />

Wyświetl plik

@ -201,3 +201,7 @@ export function MfaForm() {
export function ChatIndex() {
return import(/* webpackChunkName: "features/chats" */'../../chats');
}
export function ChatRoom() {
return import(/* webpackChunkName: "features/chats/chat_room" */'../../chats/chat_room');
}