BOD-14 Functional 2 way messaging from app.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { ShrinkOutlined } from "@ant-design/icons";
|
||||
import { Avatar, Badge, Col, List, Row } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { openConversation, toggleChatVisible } from "../../redux/messaging/messaging.actions";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
toggleChatVisible: () => dispatch(toggleChatVisible()),
|
||||
openConversation: number => dispatch(openConversation(number))
|
||||
});
|
||||
|
||||
export function ChatConversationListComponent({
|
||||
toggleChatVisible,
|
||||
conversationList,
|
||||
openConversation
|
||||
}) {
|
||||
console.log("conversationList", conversationList);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row>
|
||||
<Col span={12}>Title</Col>
|
||||
<Col span={2} offset={10}>
|
||||
<ShrinkOutlined onClick={() => toggleChatVisible()} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<List
|
||||
dataSource={conversationList}
|
||||
renderItem={item => (
|
||||
<Badge count={item.messages_aggregate.aggregate.count || 0}>
|
||||
<List.Item
|
||||
key={item.id}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() =>
|
||||
openConversation({ phone_num: item.phone_num, id: item.id })
|
||||
}>
|
||||
<List.Item.Meta
|
||||
avatar={
|
||||
<Avatar src='https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png' />
|
||||
}
|
||||
title={item.phone_num}
|
||||
description='Some sort of RO info? '
|
||||
/>
|
||||
</List.Item>
|
||||
</Badge>
|
||||
)}
|
||||
/>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ChatConversationListComponent);
|
||||
@@ -0,0 +1,16 @@
|
||||
import React from "react";
|
||||
import ChatConversationListComponent from "./chat-conversation-list.component";
|
||||
import { useSubscription } from "@apollo/react-hooks";
|
||||
import { CONVERSATION_LIST_SUBSCRIPTION } from "../../graphql/conversations.queries";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
|
||||
export default function ChatConversationListContainer() {
|
||||
const { loading, error, data } = useSubscription(
|
||||
CONVERSATION_LIST_SUBSCRIPTION
|
||||
);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
return <ChatConversationListComponent conversationList={data.conversations || []} />;
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
import { Button } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { closeConversation, sendMessage, toggleConversationVisible } from "../../redux/messaging/messaging.actions";
|
||||
import {
|
||||
closeConversation,
|
||||
sendMessage,
|
||||
toggleConversationVisible
|
||||
} from "../../redux/messaging/messaging.actions";
|
||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
@@ -18,13 +22,13 @@ function ChatConversationClosedComponent({
|
||||
}) {
|
||||
return (
|
||||
<div style={{ display: "flex" }}>
|
||||
<div onClick={() => toggleConversationVisible(conversation.phone)}>
|
||||
<PhoneFormatter>{conversation.phone}</PhoneFormatter>
|
||||
<div onClick={() => toggleConversationVisible(conversation.phone_num)}>
|
||||
<PhoneFormatter>{conversation.phone_num}</PhoneFormatter>
|
||||
</div>
|
||||
<Button
|
||||
type='dashed'
|
||||
shape='circle-outline'
|
||||
onClick={() => closeConversation(conversation.phone)}>
|
||||
onClick={() => closeConversation(conversation.phone_num)}>
|
||||
X
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, Card } from "antd";
|
||||
import { Button, Card, Badge } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -25,24 +25,26 @@ const mapDispatchToProps = dispatch => ({
|
||||
export function ChatConversationComponent({
|
||||
conversation,
|
||||
toggleConversationVisible,
|
||||
closeConversation
|
||||
closeConversation,
|
||||
messages,
|
||||
subState
|
||||
}) {
|
||||
const messages = [];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Badge count={messages.length}>
|
||||
<Card
|
||||
title={
|
||||
conversation.open ? (
|
||||
<div style={{ display: "flex" }}>
|
||||
<div
|
||||
onClick={() => toggleConversationVisible(conversation.phone)}>
|
||||
<PhoneFormatter>{conversation.phone}</PhoneFormatter>
|
||||
onClick={() =>
|
||||
toggleConversationVisible(conversation.phone_num)
|
||||
}>
|
||||
<PhoneFormatter>{conversation.phone_num}</PhoneFormatter>
|
||||
</div>
|
||||
<Button
|
||||
type='danger'
|
||||
shape='circle-outline'
|
||||
onClick={() => closeConversation(conversation.phone)}>
|
||||
onClick={() => closeConversation(conversation.phone_num)}>
|
||||
X
|
||||
</Button>
|
||||
</div>
|
||||
@@ -57,12 +59,13 @@ export function ChatConversationComponent({
|
||||
<ChatConversationOpenComponent
|
||||
messages={messages}
|
||||
conversation={conversation}
|
||||
subState={subState}
|
||||
/>
|
||||
) : (
|
||||
<ChatConversationClosedComponent conversation={conversation} />
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,33 @@
|
||||
import { useSubscription } from "@apollo/react-hooks";
|
||||
import React from "react";
|
||||
import ChatConversationComponent from "./chat-conversation.component";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { MESSAGES_SUBSCRIPTION } from "../../graphql/messages.queries";
|
||||
import ChatConversationComponent from "./chat-conversation.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
});
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function ChatConversationContainer({ conversation }) {
|
||||
console.log("conversation", conversation);
|
||||
const { loading, error, data } = useSubscription(MESSAGES_SUBSCRIPTION, {
|
||||
variables: { conversationId: conversation.id }
|
||||
});
|
||||
|
||||
return (
|
||||
<ChatConversationComponent
|
||||
subState={[loading, error]}
|
||||
conversation={conversation}
|
||||
messages={(data && data.messages) || []}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(function ChatConversationContainer({ conversation }) {
|
||||
return <ChatConversationComponent conversation={conversation} />;
|
||||
});
|
||||
)(ChatConversationContainer);
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import React from "react";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import ChatSendMessage from "../chat-send-message/chat-send-message.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
|
||||
export default function ChatConversationOpenComponent({
|
||||
conversation,
|
||||
messages
|
||||
messages,
|
||||
subState
|
||||
}) {
|
||||
if (!!!messages) return <div>No Messages</div>;
|
||||
const [loading, error] = subState;
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -12,11 +18,13 @@ export default function ChatConversationOpenComponent({
|
||||
<ul>
|
||||
{messages.map(item => (
|
||||
<li
|
||||
key={item.sid}
|
||||
className={`${
|
||||
item.direction === "inbound" ? "sent" : "replies"
|
||||
}`}>
|
||||
<p> {item.body}</p>
|
||||
key={item.id}
|
||||
className={`${item.isoutbound ? "replies" : "sent"}`}>
|
||||
<div>
|
||||
<p>
|
||||
{item.text} <br /> <i>{item.status}</i>
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
@@ -2,6 +2,8 @@ import { Badge, Card } from "antd";
|
||||
import { MessageFilled } from "@ant-design/icons";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ChatConversationListContainer from "../chat-conversation-list/chat-conversation-list.container";
|
||||
|
||||
export default function ChatWindowComponent({
|
||||
chatVisible,
|
||||
toggleChatVisible
|
||||
@@ -11,19 +13,19 @@ export default function ChatWindowComponent({
|
||||
<div>
|
||||
<Badge count={5}>
|
||||
<Card
|
||||
onClick={() => toggleChatVisible()}
|
||||
style={{
|
||||
width: chatVisible ? "300px" : "125px",
|
||||
margin: "0px 10px"
|
||||
}}
|
||||
size="small"
|
||||
>
|
||||
size='small'>
|
||||
{chatVisible ? (
|
||||
<div className="messages" style={{ height: "400px" }}>
|
||||
List of chats here.
|
||||
<div className='messages' style={{ height: "400px" }}>
|
||||
<ChatConversationListContainer />
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<div
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => toggleChatVisible()}>
|
||||
<MessageFilled />
|
||||
<strong style={{ paddingLeft: "10px" }}>
|
||||
{t("messaging.labels.messaging")}
|
||||
|
||||
@@ -12,19 +12,17 @@ import ChatOverlayComponent from "./chat-overlay.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
chatVisible: selectChatVisible,
|
||||
conversations: selectConversations
|
||||
activeConversations: selectConversations
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
toggleChatVisible: () => dispatch(toggleChatVisible())
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(function ChatWindowContainer({
|
||||
|
||||
export function ChatOverlayContainer({
|
||||
chatVisible,
|
||||
toggleChatVisible,
|
||||
conversations
|
||||
activeConversations
|
||||
}) {
|
||||
return (
|
||||
<Affix offsetBottom={0}>
|
||||
@@ -35,14 +33,20 @@ export default connect(
|
||||
toggleChatVisible={toggleChatVisible}
|
||||
/>
|
||||
</Badge>
|
||||
{conversations
|
||||
? conversations.map((conversation, idx) => (
|
||||
<Badge key={idx} count={5}>
|
||||
<ChatConversationContainer conversation={conversation} />
|
||||
</Badge>
|
||||
{activeConversations
|
||||
? activeConversations.map(conversation => (
|
||||
<ChatConversationContainer
|
||||
conversation={conversation}
|
||||
key={conversation.id}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
</div>
|
||||
</Affix>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ChatOverlayContainer);
|
||||
|
||||
@@ -19,11 +19,12 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) {
|
||||
|
||||
const handleEnter = () => {
|
||||
sendMessage({
|
||||
to: conversation.phone,
|
||||
to: conversation.phone_num,
|
||||
body: message,
|
||||
messagingServiceSid: bodyshop.messagingservicesid,
|
||||
conversationid: conversation.id
|
||||
});
|
||||
setMessage("");
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -31,6 +32,7 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) {
|
||||
<Input.TextArea
|
||||
allowClear
|
||||
autoSize={{ minRows: 1, maxRows: 4 }}
|
||||
value={message}
|
||||
placeholder={t("messaging.labels.typeamessage")}
|
||||
// enterButton={}
|
||||
onChange={e => setMessage(e.target.value)}
|
||||
|
||||
Reference in New Issue
Block a user