BOD-14 WIP. CSS issues present with 2 way texting, but working live.

This commit is contained in:
Patrick Fic
2020-03-26 17:03:22 -07:00
parent a507e40816
commit f80f96f3df
19 changed files with 244 additions and 160 deletions

View File

@@ -24,7 +24,7 @@ export function ChatConversationListComponent({
console.log("conversationList", conversationList);
return (
<div>
<div className='chat-overlay-open'>
<Row>
<Col span={12}>Title</Col>
<Col span={2} offset={10}>

View File

@@ -21,12 +21,13 @@ function ChatConversationClosedComponent({
closeConversation
}) {
return (
<div style={{ display: "flex" }}>
<div className='chat-overlay-closed'>
<div onClick={() => toggleConversationVisible(conversation.phone_num)}>
<PhoneFormatter>{conversation.phone_num}</PhoneFormatter>
</div>
<Button
type='dashed'
style={{ alignSelf: "right" }}
shape='circle-outline'
onClick={() => closeConversation(conversation.phone_num)}>
X

View File

@@ -1,60 +1,17 @@
import { Button, Card, Badge } from "antd";
import { Badge, Card } from "antd";
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
closeConversation,
sendMessage,
toggleConversationVisible
} from "../../redux/messaging/messaging.actions";
import PhoneFormatter from "../../utils/PhoneFormatter";
import ChatConversationClosedComponent from "./chat-conversation.closed.component";
import ChatConversationOpenComponent from "./chat-conversation.open.component";
import "./chat-conversation.styles.scss"; //https://bootsnipp.com/snippets/exR5v
import ChatConversationClosedComponent from "./chat-conversation.closed.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
});
const mapDispatchToProps = dispatch => ({
toggleConversationVisible: conversationId =>
dispatch(toggleConversationVisible(conversationId)),
closeConversation: phone => dispatch(closeConversation(phone)),
sendMessage: message => dispatch(sendMessage(message))
});
export function ChatConversationComponent({
export default function ChatConversationComponent({
conversation,
toggleConversationVisible,
closeConversation,
messages,
subState
}) {
return (
<Badge count={messages.length}>
<Card
title={
conversation.open ? (
<div style={{ display: "flex" }}>
<div
onClick={() =>
toggleConversationVisible(conversation.phone_num)
}>
<PhoneFormatter>{conversation.phone_num}</PhoneFormatter>
</div>
<Button
type='danger'
shape='circle-outline'
onClick={() => closeConversation(conversation.phone_num)}>
X
</Button>
</div>
) : null
}
style={{
width: conversation.open ? "400px" : "175px",
margin: "0px 10px"
}}
size='small'>
<Card className='chat-overlay' size='small'>
{conversation.open ? (
<ChatConversationOpenComponent
messages={messages}
@@ -68,8 +25,3 @@ export function ChatConversationComponent({
</Badge>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ChatConversationComponent);

View File

@@ -13,7 +13,6 @@ const mapDispatchToProps = dispatch => ({
});
export function ChatConversationContainer({ conversation }) {
console.log("conversation", conversation);
const { loading, error, data } = useSubscription(MESSAGES_SUBSCRIPTION, {
variables: { conversationId: conversation.id }
});

View File

@@ -1,7 +1,8 @@
import React from "react";
import React, { useEffect, useRef } 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";
import { CheckOutlined, CheckCircleOutlined } from "@ant-design/icons";
export default function ChatConversationOpenComponent({
conversation,
@@ -9,24 +10,47 @@ export default function ChatConversationOpenComponent({
subState
}) {
const [loading, error] = subState;
const messagesEndRef = useRef(null);
const scrollToBottom = () => {
console.log("use");
!!messagesEndRef.current &&
messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
};
useEffect(scrollToBottom, [messages]);
if (loading) return <LoadingSpinner />;
if (error) return <AlertComponent message={error.message} type='error' />;
const StatusRender = status => {
switch (status) {
case "sent":
return <CheckOutlined style={{ margin: "2px", float: "right" }} />;
case "delivered":
return (
<CheckCircleOutlined style={{ margin: "2px", float: "right" }} />
);
default:
return null;
}
};
return (
<div>
<div className='messages' style={{ height: "400px" }}>
<div className='chat-overlay-open'>
<div className='messages'>
<ul>
{messages.map(item => (
<li
key={item.id}
className={`${item.isoutbound ? "replies" : "sent"}`}>
<div>
<p>
{item.text} <br /> <i>{item.status}</i>
</p>
</div>
<p>
{item.text}
{StatusRender(item.status)}
</p>
</li>
))}
<li ref={messagesEndRef} />
</ul>
</div>
<ChatSendMessage conversation={conversation} />

View File

@@ -1,6 +1,77 @@
.chat-overlay-wrapper {
width: 95vw;
}
.chat-overlay-scroller {
overflow-x: scroll;
overflow-y: hidden;
vertical-align: bottom;
}
.chat-overlay {
margin: 0px 12px;
display: inline-block;
}
.chat-overlay-open {
width: 400px;
height: 33vh;
display: flex;
flex-flow: column;
}
.chat-overlay-closed {
display: flex;
justify-content: space-between;
vertical-align: middle;
width: 150px;
cursor: pointer;
}
// .chat-messages {
// height: 80%;
// overflow-x: hidden;
// overflow-y: scroll;
// flex-grow: 1;
// ul {
// list-style: none;
// margin: 0;
// padding: 0;
// }
// ul li {
// display: inline-block;
// clear: both;
// padding: 3px 10px;
// border-radius: 30px;
// margin-bottom: 2px;
// }
// .inbound {
// background: #eee;
// float: left;
// }
// .outbound {
// float: right;
// background: #0084ff;
// color: #fff;
// }
// .inbound + .outbound {
// border-bottom-right-radius: 5px;
// }
// .outbound + .outbound {
// border-top-right-radius: 5px;
// border-bottom-right-radius: 5px;
// }
// .outbound:last-of-type {
// border-bottom-right-radius: 30px;
// }
// }
.messages {
height: auto;
min-height: calc(100% - 93px);
min-height: calc(100% - 10px);
max-height: calc(100% - 93px);
overflow-y: scroll;
overflow-x: hidden;
@@ -21,7 +92,7 @@
display: inline-block;
clear: both;
//float: left;
margin: 5px 15px 5px 15px;
margin: 5px;
width: calc(100% - 25px);
font-size: 0.9em;
}

View File

@@ -1,5 +1,5 @@
import { Badge, Card } from "antd";
import { MessageFilled } from "@ant-design/icons";
import { Card } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import ChatConversationListContainer from "../chat-conversation-list/chat-conversation-list.container";
@@ -10,30 +10,21 @@ export default function ChatWindowComponent({
}) {
const { t } = useTranslation();
return (
<div>
<Badge count={5}>
<Card
style={{
width: chatVisible ? "300px" : "125px",
margin: "0px 10px"
}}
size='small'>
{chatVisible ? (
<div className='messages' style={{ height: "400px" }}>
<ChatConversationListContainer />
</div>
) : (
<div
style={{ cursor: "pointer" }}
onClick={() => toggleChatVisible()}>
<MessageFilled />
<strong style={{ paddingLeft: "10px" }}>
{t("messaging.labels.messaging")}
</strong>
</div>
)}
</Card>
</Badge>
</div>
<Card
className="chat-overlay"
size='small'>
{chatVisible ? (
<ChatConversationListContainer />
) : (
<div className="chat-overlay-closed" onClick={() => toggleChatVisible()}>
<MessageFilled />
<strong style={{ paddingLeft: "10px" }}>
{t("messaging.labels.messaging")}
</strong>
</div>
)}
</Card>
);
}

View File

@@ -26,21 +26,23 @@ export function ChatOverlayContainer({
}) {
return (
<Affix offsetBottom={0}>
<div>
<Badge count={10}>
<ChatOverlayComponent
chatVisible={chatVisible}
toggleChatVisible={toggleChatVisible}
/>
</Badge>
{activeConversations
? activeConversations.map(conversation => (
<ChatConversationContainer
conversation={conversation}
key={conversation.id}
/>
))
: null}
<div className={`chat-overlay-wrapper`}>
<div className={`chat-overlay-scroller`}>
<Badge count={10}>
<ChatOverlayComponent
chatVisible={chatVisible}
toggleChatVisible={toggleChatVisible}
/>
</Badge>
{activeConversations
? activeConversations.map(conversation => (
<ChatConversationContainer
conversation={conversation}
key={conversation.id}
/>
))
: null}
</div>
</div>
</Affix>
);

View File

@@ -1,5 +1,6 @@
import { Input } from "antd";
import React, { useState } from "react";
import { Input, Spin } from "antd";
import { LoadingOutlined } from "@ant-design/icons";
import React, { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -15,6 +16,12 @@ const mapDispatchToProps = dispatch => ({
function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) {
const [message, setMessage] = useState("");
useEffect(() => {
if (conversation.isSending === false) {
setMessage("");
}
}, [conversation, setMessage]);
const { t } = useTranslation();
const handleEnter = () => {
@@ -24,22 +31,35 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) {
messagingServiceSid: bodyshop.messagingservicesid,
conversationid: conversation.id
});
setMessage("");
};
return (
<div style={{ display: "flex " }}>
<Input.TextArea
allowClear
autoFocus
suffix={<span>a</span>}
autoSize={{ minRows: 1, maxRows: 4 }}
value={message}
disabled={conversation.isSending}
placeholder={t("messaging.labels.typeamessage")}
// enterButton={}
onChange={e => setMessage(e.target.value)}
onPressEnter={event => {
event.preventDefault();
if (!!!event.shiftKey) handleEnter();
}}
/>
<Spin
style={{ display: `${conversation.isSending ? "" : "none"}` }}
indicator={
<LoadingOutlined
style={{
fontSize: 24
}}
spin
/>
}
/>
</div>
);
}

View File

@@ -13,10 +13,11 @@ const Sdiv = styled.div`
width: 80%;
top: 10%;
left: 10%;
// background-color: #ffcc00;
// background-color: #ffcc00;
`;
const ResponsiveReactGridLayout = WidthProvider(Responsive);
export default function DashboardGridComponent() {
const [state, setState] = useState({
layout: [
@@ -38,19 +39,18 @@ export default function DashboardGridComponent() {
console.log("breakpoint, cols", breakpoint, cols);
// setState({ ...state, breakpoint: breakpoint, cols: cols });
};
if (true) return null;
return (
<Sdiv>
The Grid.
<ResponsiveReactGridLayout
{...defaultProps}
onBreakpointChange={onBreakpointChange}
width="100%"
width='100%'
onLayoutChange={layout => {
console.log("layout", layout);
setState({ ...state, layout });
}}
>
}}>
{state.layout.map((item, index) => {
return (
<Card style={{ width: "100px" }} key={item.i} data-grid={item}>