From bf4265518645c5906740df9d7d86f21fdf2ac988 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 30 Apr 2020 11:40:41 -0700 Subject: [PATCH] BOD-14 Fixed some broken UI with temporary hard coded valeus. Added basic Chat tagging features --- ...chat-conversation-title-tags.component.jsx | 16 ++ .../chat-conversation-title.component.jsx | 15 ++ .../chat-conversation.component.jsx | 23 +- .../chat-conversation.container.jsx | 25 +- .../chat-message-list.styles.scss | 235 +++++++++--------- .../chat-send-message.component.jsx | 20 +- .../chat-tag-ro/chat-tag-ro.component.jsx | 38 +++ .../chat-tag-ro/chat-tag-ro.container.jsx | 46 ++++ client/src/graphql/conversations.queries.js | 8 + .../src/graphql/job-conversations.queries.js | 14 ++ client/src/graphql/jobs.queries.js | 11 + 11 files changed, 298 insertions(+), 153 deletions(-) create mode 100644 client/src/components/chat-conversation-title-tags/chat-conversation-title-tags.component.jsx create mode 100644 client/src/components/chat-conversation-title/chat-conversation-title.component.jsx create mode 100644 client/src/components/chat-tag-ro/chat-tag-ro.component.jsx create mode 100644 client/src/components/chat-tag-ro/chat-tag-ro.container.jsx create mode 100644 client/src/graphql/job-conversations.queries.js diff --git a/client/src/components/chat-conversation-title-tags/chat-conversation-title-tags.component.jsx b/client/src/components/chat-conversation-title-tags/chat-conversation-title-tags.component.jsx new file mode 100644 index 000000000..f185aaa14 --- /dev/null +++ b/client/src/components/chat-conversation-title-tags/chat-conversation-title-tags.component.jsx @@ -0,0 +1,16 @@ +import React from "react"; +import { Tag } from "antd"; +import { Link } from "react-router-dom"; +export default function ChatConversationTitleTags({ jobConversations }) { + return ( +
+ {jobConversations.map((item) => ( + + + {item.job.ro_number || "?"} + + + ))} +
+ ); +} diff --git a/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx b/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx new file mode 100644 index 000000000..b28c1d298 --- /dev/null +++ b/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx @@ -0,0 +1,15 @@ +import React from "react"; +import ChatTagRoContainer from "../chat-tag-ro/chat-tag-ro.container"; +import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conversation-title-tags.component"; + +export default function ChatConversationTitle({ conversation }) { + return ( +
+ {conversation.phone_num} + + +
+ ); +} diff --git a/client/src/components/chat-conversation/chat-conversation.component.jsx b/client/src/components/chat-conversation/chat-conversation.component.jsx index c9445ef63..5ff01b68a 100644 --- a/client/src/components/chat-conversation/chat-conversation.component.jsx +++ b/client/src/components/chat-conversation/chat-conversation.component.jsx @@ -4,24 +4,33 @@ import ChatMessageListComponent from "../chat-messages-list/chat-message-list.co import ChatSendMessage from "../chat-send-message/chat-send-message.component"; import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component.jsx"; import AlertComponent from "../alert/alert.component"; +import ChatConversationTitle from "../chat-conversation-title/chat-conversation-title.component"; -export default function ChatConversationComponent({ - messages, - subState, - conversation, - unreadCount, -}) { +export default function ChatConversationComponent({ subState, conversation }) { const [loading, error] = subState; if (loading) return ; if (error) return ; + const unreadCount = + (conversation && + conversation && + conversation.messages_aggregate && + conversation.messages_aggregate.aggregate && + conversation.messages_aggregate.aggregate.count) || + 0; + + const messages = + (conversation && conversation.messages) || + []; + return (
- + +
diff --git a/client/src/components/chat-conversation/chat-conversation.container.jsx b/client/src/components/chat-conversation/chat-conversation.container.jsx index f3ee27d8d..22b88e4df 100644 --- a/client/src/components/chat-conversation/chat-conversation.container.jsx +++ b/client/src/components/chat-conversation/chat-conversation.container.jsx @@ -27,28 +27,9 @@ export function ChatConversationContainer({ selectedConversation }) { return ( ); } diff --git a/client/src/components/chat-messages-list/chat-message-list.styles.scss b/client/src/components/chat-messages-list/chat-message-list.styles.scss index bb66601e6..57129a7b9 100644 --- a/client/src/components/chat-messages-list/chat-message-list.styles.scss +++ b/client/src/components/chat-messages-list/chat-message-list.styles.scss @@ -1,128 +1,127 @@ .messages { - height: auto; - min-height: calc(100% - 10px); - max-height: calc(100% - 93px); - overflow-y: scroll; - overflow-x: hidden; - } - @media screen and (max-width: 735px) { - .messages { - max-height: calc(100% - 105px); - } - } - .messages::-webkit-scrollbar { - width: 8px; - background: transparent; - } - .messages::-webkit-scrollbar-thumb { - background-color: rgba(0, 0, 0, 0.3); - } - .messages ul li { - display: inline-block; - clear: both; - //float: left; - margin: 5px; - width: calc(100% - 25px); - font-size: 0.9em; - } - .messages ul li:nth-last-child(1) { - margin-bottom: 20px; - } - .messages ul li.sent img { - margin: 6px 8px 0 0; - } - .messages ul li.sent p { - background: #435f7a; - color: #f5f5f5; - } - .messages ul li.replies img { - float: right; - margin: 6px 0 0 8px; - } - .messages ul li.replies p { - background: #f5f5f5; - float: right; - } - .messages ul li img { - width: 22px; - border-radius: 50%; - float: left; + height: 350px; + min-height: calc(100% - 10px); + max-height: calc(100% - 93px); + overflow-y: scroll; + overflow-x: hidden; +} +@media screen and (max-width: 735px) { + .messages { + max-height: calc(100% - 105px); } +} +.messages::-webkit-scrollbar { + width: 8px; + background: transparent; +} +.messages::-webkit-scrollbar-thumb { + background-color: rgba(0, 0, 0, 0.3); +} +.messages ul li { + display: inline-block; + clear: both; + //float: left; + margin: 5px; + width: calc(100% - 25px); + font-size: 0.9em; +} +.messages ul li:nth-last-child(1) { + margin-bottom: 20px; +} +.messages ul li.sent img { + margin: 6px 8px 0 0; +} +.messages ul li.sent p { + background: #435f7a; + color: #f5f5f5; +} +.messages ul li.replies img { + float: right; + margin: 6px 0 0 8px; +} +.messages ul li.replies p { + background: #f5f5f5; + float: right; +} +.messages ul li img { + width: 22px; + border-radius: 50%; + float: left; +} +.messages ul li p { + display: inline-block; + padding: 10px 15px; + border-radius: 20px; + max-width: 205px; + line-height: 130%; +} +@media screen and (min-width: 735px) { .messages ul li p { - display: inline-block; - padding: 10px 15px; - border-radius: 20px; - max-width: 205px; - line-height: 130%; - } - @media screen and (min-width: 735px) { - .messages ul li p { - max-width: 300px; - } - } - .message-input { - position: absolute; - bottom: 0; - width: 100%; - z-index: 99; - } - .message-input .wrap { - position: relative; + max-width: 300px; } +} +.message-input { + position: absolute; + bottom: 0; + width: 100%; + z-index: 99; +} +.message-input .wrap { + position: relative; +} +.message-input .wrap input { + font-family: "proxima-nova", "Source Sans Pro", sans-serif; + float: left; + border: none; + width: calc(100% - 90px); + padding: 11px 32px 10px 8px; + font-size: 0.8em; + color: #32465a; +} +@media screen and (max-width: 735px) { .message-input .wrap input { - font-family: "proxima-nova", "Source Sans Pro", sans-serif; - float: left; - border: none; - width: calc(100% - 90px); - padding: 11px 32px 10px 8px; - font-size: 0.8em; - color: #32465a; - } - @media screen and (max-width: 735px) { - .message-input .wrap input { - padding: 15px 32px 16px 8px; - } - } - .message-input .wrap input:focus { - outline: none; + padding: 15px 32px 16px 8px; } +} +.message-input .wrap input:focus { + outline: none; +} +.message-input .wrap .attachment { + position: absolute; + right: 60px; + z-index: 4; + margin-top: 10px; + font-size: 1.1em; + color: #435f7a; + opacity: 0.5; + cursor: pointer; +} +@media screen and (max-width: 735px) { .message-input .wrap .attachment { - position: absolute; - right: 60px; - z-index: 4; - margin-top: 10px; - font-size: 1.1em; - color: #435f7a; - opacity: 0.5; - cursor: pointer; - } - @media screen and (max-width: 735px) { - .message-input .wrap .attachment { - margin-top: 17px; - right: 65px; - } - } - .message-input .wrap .attachment:hover { - opacity: 1; + margin-top: 17px; + right: 65px; } +} +.message-input .wrap .attachment:hover { + opacity: 1; +} +.message-input .wrap button { + float: right; + border: none; + width: 50px; + padding: 12px 0; + cursor: pointer; + background: #32465a; + color: #f5f5f5; +} +@media screen and (max-width: 735px) { .message-input .wrap button { - float: right; - border: none; - width: 50px; - padding: 12px 0; - cursor: pointer; - background: #32465a; - color: #f5f5f5; + padding: 16px 0; } - @media screen and (max-width: 735px) { - .message-input .wrap button { - padding: 16px 0; - } - } - .message-input .wrap button:hover { - background: #435f7a; - } - .message-input .wrap button:focus { - outline: none; - } - \ No newline at end of file +} +.message-input .wrap button:hover { + background: #435f7a; +} +.message-input .wrap button:focus { + outline: none; +} diff --git a/client/src/components/chat-send-message/chat-send-message.component.jsx b/client/src/components/chat-send-message/chat-send-message.component.jsx index e2eb91e83..ca43dbf73 100644 --- a/client/src/components/chat-send-message/chat-send-message.component.jsx +++ b/client/src/components/chat-send-message/chat-send-message.component.jsx @@ -6,22 +6,30 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { sendMessage } from "../../redux/messaging/messaging.actions"; import { selectBodyshop } from "../../redux/user/user.selectors"; +import { selectIsSending } from "../../redux/messaging/messaging.selectors"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, + isSending: selectIsSending, }); const mapDispatchToProps = (dispatch) => ({ sendMessage: (message) => dispatch(sendMessage(message)), }); -function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) { +function ChatSendMessageComponent({ + conversation, + bodyshop, + sendMessage, + isSending, +}) { const [message, setMessage] = useState(""); useEffect(() => { - if (conversation.isSending === false) { + if (isSending === false) { setMessage(""); } - }, [conversation, setMessage]); + }, [isSending, setMessage]); + const { t } = useTranslation(); const handleEnter = () => { @@ -29,7 +37,7 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) { to: conversation.phone_num, body: message, messagingServiceSid: bodyshop.messagingservicesid, - conversationid: conversation.conversationId, + conversationid: conversation.id, }); }; @@ -41,7 +49,7 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) { suffix={a} autoSize={{ minRows: 1, maxRows: 4 }} value={message} - disabled={conversation.isSending} + disabled={isSending} placeholder={t("messaging.labels.typeamessage")} onChange={(e) => setMessage(e.target.value)} onPressEnter={(event) => { @@ -50,7 +58,7 @@ function ChatSendMessageComponent({ conversation, bodyshop, sendMessage }) { }} /> { + setSearchQuery(value); + }; + + const handleKeyDown = (event) => { + if (event.key === "Enter") { + executeSearch(); + } + }; + + return ( + : null} + style={{ width: 200 }} + onSearch={handleSearchQuery} + onSelect={handleInsertTag} + onKeyDown={handleKeyDown}> + {roOptions.map((item, idx) => ( + + {` ${item.ro_number || ""} | ${item.ownr_fn || ""} ${ + item.ownr_ln || "" + }`} + + ))} + + ); +} diff --git a/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx b/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx new file mode 100644 index 000000000..45c63a599 --- /dev/null +++ b/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx @@ -0,0 +1,46 @@ +import React, { useState } from "react"; +import ChatTagRo from "./chat-tag-ro.component"; +import { useLazyQuery, useMutation } from "@apollo/react-hooks"; +import { SEARCH_FOR_JOBS } from "../../graphql/jobs.queries"; +import { INSERT_CONVERSATION_TAG } from "../../graphql/job-conversations.queries"; +export default function ChatTagRoContainer({ conversation }) { + console.log("ChatTagRoContainer -> conversation", conversation); + + const searchQueryState = useState(""); + const searchText = searchQueryState[0]; + + const [loadRo, { called, loading, data, refetch }] = useLazyQuery( + SEARCH_FOR_JOBS, + { + variables: { search: `%${searchText}%` }, + } + ); + + const executeSearch = () => { + if (called) refetch(); + else { + loadRo(); + } + }; + + const [insertTag] = useMutation(INSERT_CONVERSATION_TAG, { + variables: { conversationId: conversation.id }, + }); + + const handleInsertTag = (value, option) => { + console.log("value, option", value, option); + insertTag({ variables: { jobId: option.key } }); + }; + + return ( +
+ +
+ ); +} diff --git a/client/src/graphql/conversations.queries.js b/client/src/graphql/conversations.queries.js index f0ad0cfa7..a34415f0d 100644 --- a/client/src/graphql/conversations.queries.js +++ b/client/src/graphql/conversations.queries.js @@ -34,6 +34,14 @@ export const CONVERSATION_SUBSCRIPTION_BY_PK = gql` } id phone_num + job_conversations { + jobid + conversationid + job { + id + ro_number + } + } } } `; diff --git a/client/src/graphql/job-conversations.queries.js b/client/src/graphql/job-conversations.queries.js new file mode 100644 index 000000000..d0072aee0 --- /dev/null +++ b/client/src/graphql/job-conversations.queries.js @@ -0,0 +1,14 @@ +import { gql } from "apollo-boost"; + +export const INSERT_CONVERSATION_TAG = gql` + mutation INSERT_CONVERSATION_TAG($conversationId: uuid!, $jobId: uuid!) { + insert_job_conversations( + objects: { conversationid: $conversationId, jobid: $jobId } + ) { + returning { + jobid + conversationid + } + } + } +`; diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index b213e6583..d204ca8fb 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -432,6 +432,17 @@ export const ACTIVE_JOBS_FOR_AUTOCOMPLETE = gql` } `; +export const SEARCH_FOR_JOBS = gql` + query SEARCH_FOR_JOBS($search: String!) { + jobs(where: { ro_number: { _ilike: $search } }) { + id + ro_number + ownr_fn + ownr_ln + } + } +`; + //TODO Ensure this is always up to date. export const QUERY_ALL_JOB_FIELDS = gql` query QUERY_ALL_JOB_FIELDS($id: uuid!) {