From 364cf6c7bb509829cefa637abbe4a3603f889e41 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Fri, 28 Aug 2020 12:53:19 -0700 Subject: [PATCH] Added sorting to msgs sub and added some styling for messaging items. BOD-309 BOD-310 --- .../chat-affix/chat-affix.container.jsx | 6 +- .../chat-affix/chat-affix.styles.scss | 6 ++ .../chat-conversation-list.component.jsx | 78 ++++++++++--------- .../chat-conversation-list.styles.scss | 14 ++++ ...chat-conversation-title-tags.component.jsx | 9 ++- .../chat-conversation-title.component.jsx | 23 ++---- .../chat-message-list.styles.scss | 10 ++- .../chat-popup/chat-popup.component.jsx | 2 +- .../chat-popup/chat-popup.styles.scss | 6 +- .../chat-presets/chat-presets.component.jsx | 17 +--- .../chat-send-message.component.jsx | 4 + .../chat-tag-ro/chat-tag-ro.component.jsx | 45 +++++------ .../chat-tag-ro/chat-tag-ro.container.jsx | 44 +++++------ .../job-search-select.component.jsx | 11 ++- client/src/graphql/conversations.queries.js | 2 +- client/src/graphql/jobs.queries.js | 2 +- .../1598634176882_run_sql_migration/down.yaml | 1 + .../1598634176882_run_sql_migration/up.yaml | 9 +++ .../1598634335411_run_sql_migration/down.yaml | 1 + .../1598634335411_run_sql_migration/up.yaml | 9 +++ 20 files changed, 165 insertions(+), 134 deletions(-) create mode 100644 hasura/migrations/1598634176882_run_sql_migration/down.yaml create mode 100644 hasura/migrations/1598634176882_run_sql_migration/up.yaml create mode 100644 hasura/migrations/1598634335411_run_sql_migration/down.yaml create mode 100644 hasura/migrations/1598634335411_run_sql_migration/up.yaml diff --git a/client/src/components/chat-affix/chat-affix.container.jsx b/client/src/components/chat-affix/chat-affix.container.jsx index 15c270650..f2420e8fa 100644 --- a/client/src/components/chat-affix/chat-affix.container.jsx +++ b/client/src/components/chat-affix/chat-affix.container.jsx @@ -10,11 +10,13 @@ import "./chat-affix.styles.scss"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; +import { selectChatVisible } from "../../redux/messaging/messaging.selectors"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, + chatVisible: selectChatVisible, }); -export function ChatAffixContainer({ bodyshop }) { +export function ChatAffixContainer({ bodyshop, chatVisible }) { const { loading, error, data } = useSubscription( CONVERSATION_LIST_SUBSCRIPTION, { @@ -26,7 +28,7 @@ export function ChatAffixContainer({ bodyshop }) { if (error) return ; return ( - +
{bodyshop && bodyshop.messagingservicesid ? ( ( - setSelectedConversation(item.id)} - className={`chat-list-item ${ - item.id === selectedConversation - ? "chat-list-selected-conversation" - : null - }`} - > - {item.phone_num}} - description={ - item.job_conversations.length > 0 ? ( -
- {item.job_conversations.map( - (j) => - `${j.job.ownr_fn || ""} ${j.job.ownr_ln || ""} ${ - j.job.ownr_co_nm || "" - }` - )} -
- ) : ( - t("messaging.labels.nojobs") - ) - } - /> - -
- )} - /> +
+ ( + setSelectedConversation(item.id)} + className={`chat-list-item ${ + item.id === selectedConversation + ? "chat-list-selected-conversation" + : null + }`} + > + {item.job_conversations.length > 0 ? ( +
+ {item.job_conversations.map((j, idx) => ( + + {`${j.job.ownr_fn || ""} ${j.job.ownr_ln || ""} ${ + j.job.ownr_co_nm || "" + } `} + + ))} +
+ ) : ( + {item.phone_num} + )} + {item.job_conversations.length > 0 + ? item.job_conversations.map((j, idx) => ( + + {j.job.ro_number} + + )) + : null} + +
+ )} + /> +
); } export default connect( diff --git a/client/src/components/chat-conversation-list/chat-conversation-list.styles.scss b/client/src/components/chat-conversation-list/chat-conversation-list.styles.scss index 724f1daf6..bfc83d947 100644 --- a/client/src/components/chat-conversation-list/chat-conversation-list.styles.scss +++ b/client/src/components/chat-conversation-list/chat-conversation-list.styles.scss @@ -1,10 +1,24 @@ .chat-list-selected-conversation { background-color: rgba(128, 128, 128, 0.2); } +.chat-list-container { + flex: 1; + overflow: auto; + height: 100%; +} .chat-list-item { + display: flex; + flex-direction: row; &:hover { cursor: pointer; color: #ff7a00; } + .chat-name { + flex: 1; + display: inline; + } + .ro-number-tag { + align-self: baseline; + } } 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 index af6acb11b..2051bf5ae 100644 --- 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 @@ -29,11 +29,14 @@ export default function ChatConversationTitleTags({ jobConversations }) { handleRemoveTag(item.job.id)}> + onClose={() => handleRemoveTag(item.job.id)} + > - {item.job.ro_number || "?"} + {`${item.job.ro_number || "?"} | ${item.job.ownr_fn || ""} ${ + item.job.ownr_ln || "" + } ${item.job.ownr_co_nm || ""}`} ))} 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 index 1d06f03cd..61cc3147c 100644 --- a/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx +++ b/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx @@ -1,32 +1,23 @@ -import { Space } from "antd"; import React from "react"; +import PhoneNumberFormatter from "../../utils/PhoneFormatter"; import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conversation-title-tags.component"; import ChatTagRoContainer from "../chat-tag-ro/chat-tag-ro.container"; -import ChatPresetsComponent from "../chat-presets/chat-presets.component"; export default function ChatConversationTitle({ conversation }) { return (
- - {conversation && conversation.phone_num} - - {conversation && - conversation.job_conversations.map( - (j) => - `${j.job.ownr_fn || ""} ${j.job.ownr_ln || ""} ${ - j.job.ownr_co_nm || "" - } | ` - )} - - -
+
- +
+
+ + {conversation && conversation.phone_num} +
); 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 7677012a8..f945a5556 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 @@ -3,9 +3,12 @@ // bottom: 0rem; color: whitesmoke; border: #000000; - margin-left: 0.2rem; - margin-right: 0rem; - // z-index: 5; + position: absolute; + margin: 0 0.1rem; + bottom: 0.1rem; + right: 0.3rem; + + z-index: 5; } .chat { @@ -84,6 +87,7 @@ background: linear-gradient(to bottom, #00d0ea 0%, #0085d1 100%); background-attachment: fixed; position: relative; + padding-bottom: 0.6rem; } .mine .message.last:before { diff --git a/client/src/components/chat-popup/chat-popup.component.jsx b/client/src/components/chat-popup/chat-popup.component.jsx index c631936fe..51eaa4f5e 100644 --- a/client/src/components/chat-popup/chat-popup.component.jsx +++ b/client/src/components/chat-popup/chat-popup.component.jsx @@ -33,7 +33,7 @@ export function ChatPopupComponent({ style={{ position: "absolute", right: ".5rem", top: ".5rem" }} /> - + diff --git a/client/src/components/chat-popup/chat-popup.styles.scss b/client/src/components/chat-popup/chat-popup.styles.scss index e10e8df18..398762700 100644 --- a/client/src/components/chat-popup/chat-popup.styles.scss +++ b/client/src/components/chat-popup/chat-popup.styles.scss @@ -6,8 +6,12 @@ } .chat-popup-content { - //height: 50vh; + min-height: 0px; /* IMPORTANT: you need this for non-chrome browsers */ flex: 1; + //height: 100%; + .ant-col { + height: 100%; + } } @media only screen and (min-width: 992px) { diff --git a/client/src/components/chat-presets/chat-presets.component.jsx b/client/src/components/chat-presets/chat-presets.component.jsx index 70ea96406..08ddc1b26 100644 --- a/client/src/components/chat-presets/chat-presets.component.jsx +++ b/client/src/components/chat-presets/chat-presets.component.jsx @@ -1,7 +1,6 @@ -import { DownOutlined } from "@ant-design/icons"; +import { PlusCircleOutlined } from "@ant-design/icons"; import { Dropdown, Menu } from "antd"; import React from "react"; -import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { setMessage } from "../../redux/messaging/messaging.actions"; @@ -16,9 +15,7 @@ const mapDispatchToProps = (dispatch) => ({ setMessage: (message) => dispatch(setMessage(message)), }); -export function ChatPresetsComponent({ bodyshop, setMessage }) { - const { t } = useTranslation(); - +export function ChatPresetsComponent({ bodyshop, setMessage, className }) { const menu = ( {bodyshop.md_messaging_presets.map((i, idx) => ( @@ -30,15 +27,9 @@ export function ChatPresetsComponent({ bodyshop, setMessage }) { ); return ( -
+ ); 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 810777688..646c69777 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 @@ -14,6 +14,7 @@ import { selectMessage, } from "../../redux/messaging/messaging.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; +import ChatPresetsComponent from "../chat-presets/chat-presets.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -53,6 +54,8 @@ function ChatSendMessageComponent({ return (
+ + + { - setSearchQuery(value); - }; - - const handleKeyDown = (event) => { - if (event.key === "Enter") { - executeSearch(); - } - }; - return ( - - + + {loading ? : null} + {loading ? ( ) : ( setVisible(false)} /> )} - +
); } 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 index 80b06af89..6a84cd2a1 100644 --- a/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx +++ b/client/src/components/chat-tag-ro/chat-tag-ro.container.jsx @@ -1,32 +1,29 @@ -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"; -import { Tag } from "antd"; -import { useTranslation } from "react-i18next"; import { PlusOutlined } from "@ant-design/icons"; +import { useLazyQuery, useMutation } from "@apollo/react-hooks"; +import { Tag } from "antd"; +import _ from "lodash"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; import { logImEXEvent } from "../../firebase/firebase.utils"; +import { INSERT_CONVERSATION_TAG } from "../../graphql/job-conversations.queries"; +import { SEARCH_FOR_JOBS } from "../../graphql/jobs.queries"; +import ChatTagRo from "./chat-tag-ro.component"; export default function ChatTagRoContainer({ conversation }) { const { t } = useTranslation(); const [visible, setVisible] = useState(false); - const searchQueryState = useState(""); - const searchText = searchQueryState[0]; - const [loadRo, { called, loading, data, refetch }] = useLazyQuery( - SEARCH_FOR_JOBS, - { - variables: { search: `%${searchText}%` }, - } - ); + const [loadRo, { loading, data }] = useLazyQuery(SEARCH_FOR_JOBS); - const executeSearch = () => { - logImEXEvent("messaging_search_job_tag", { searchTerm: searchText }); - if (called) refetch(); - else { - loadRo(); - } + const executeSearch = (v) => { + logImEXEvent("messaging_search_job_tag", { searchTerm: v }); + loadRo(v); + }; + + const debouncedExecuteSearch = _.debounce(executeSearch, 800); + + const handleSearch = (value) => { + debouncedExecuteSearch({ variables: { search: value } }); }; const [insertTag] = useMutation(INSERT_CONVERSATION_TAG, { @@ -45,7 +42,7 @@ export default function ChatTagRoContainer({ conversation }) { conversation.job_conversations.map((i) => i.jobid); const roOptions = data - ? data.jobs.filter((job) => !existingJobTags.includes(job.id)) + ? data.search_jobs.filter((job) => !existingJobTags.includes(job.id)) : []; return ( @@ -53,9 +50,8 @@ export default function ChatTagRoContainer({ conversation }) { {visible ? ( diff --git a/client/src/components/job-search-select/job-search-select.component.jsx b/client/src/components/job-search-select/job-search-select.component.jsx index b730c6f2e..1db4244b4 100644 --- a/client/src/components/job-search-select/job-search-select.component.jsx +++ b/client/src/components/job-search-select/job-search-select.component.jsx @@ -1,12 +1,12 @@ +import { LoadingOutlined } from "@ant-design/icons"; import { useLazyQuery } from "@apollo/react-hooks"; -import { Select } from "antd"; +import { Empty, Select } from "antd"; +import _ from "lodash"; import React, { forwardRef, useEffect, useState } from "react"; import { - SEARCH_JOBS_FOR_AUTOCOMPLETE, SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE, + SEARCH_JOBS_FOR_AUTOCOMPLETE, } from "../../graphql/jobs.queries"; -import { LoadingOutlined } from "@ant-design/icons"; -import _ from "lodash"; import AlertComponent from "../alert/alert.component"; const { Option } = Select; @@ -33,7 +33,6 @@ const JobSearchSelect = ({ value, onChange, onBlur, disabled }, ref) => { useEffect(() => { if (value === option) { - console.log("Job ID Provided, searching..."); callIdSearch({ variables: { id: value } }); } }, [value, option, callIdSearch]); @@ -71,7 +70,7 @@ const JobSearchSelect = ({ value, onChange, onBlur, disabled }, ref) => { onSearch={handleSearch} // onChange={setOption} onSelect={handleSelect} - notFoundContent={loading ? : null} + notFoundContent={loading ? : } onBlur={onBlur} > {theOptions diff --git a/client/src/graphql/conversations.queries.js b/client/src/graphql/conversations.queries.js index ecdbc4e5e..571fd8c3c 100644 --- a/client/src/graphql/conversations.queries.js +++ b/client/src/graphql/conversations.queries.js @@ -2,7 +2,7 @@ import gql from "graphql-tag"; export const CONVERSATION_LIST_SUBSCRIPTION = gql` subscription CONVERSATION_LIST_SUBSCRIPTION { - conversations { + conversations(order_by: { updated_at: desc }, limit: 100) { phone_num id job_conversations { diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index 616249837..4d3971c78 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -711,7 +711,7 @@ export const SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE = gql` export const SEARCH_FOR_JOBS = gql` query SEARCH_FOR_JOBS($search: String!) { - jobs(where: { ro_number: { _ilike: $search } }) { + search_jobs(args: { search: $search }) { id ro_number ownr_fn diff --git a/hasura/migrations/1598634176882_run_sql_migration/down.yaml b/hasura/migrations/1598634176882_run_sql_migration/down.yaml new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/hasura/migrations/1598634176882_run_sql_migration/down.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/migrations/1598634176882_run_sql_migration/up.yaml b/hasura/migrations/1598634176882_run_sql_migration/up.yaml new file mode 100644 index 000000000..612eac420 --- /dev/null +++ b/hasura/migrations/1598634176882_run_sql_migration/up.yaml @@ -0,0 +1,9 @@ +- args: + cascade: true + read_only: false + sql: "CREATE OR REPLACE FUNCTION update_conversation_on_message()\nRETURNS TRIGGER + AS $$\nBEGIN\n UPDATE conversations SET last_updated = now() WHERE id = NEW.\"conversationid\";\n + \ RETURN NEW; \nEND;\n$$ language 'plpgsql';\n\nDROP TRIGGER IF EXISTS trigger_update_conversation_on_message + ON messages;\nCREATE TRIGGER trigger_update_conversation_on_message AFTER INSERT + ON messages FOR EACH ROW EXECUTE PROCEDURE update_conversation_on_message();" + type: run_sql diff --git a/hasura/migrations/1598634335411_run_sql_migration/down.yaml b/hasura/migrations/1598634335411_run_sql_migration/down.yaml new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/hasura/migrations/1598634335411_run_sql_migration/down.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/migrations/1598634335411_run_sql_migration/up.yaml b/hasura/migrations/1598634335411_run_sql_migration/up.yaml new file mode 100644 index 000000000..699642c6c --- /dev/null +++ b/hasura/migrations/1598634335411_run_sql_migration/up.yaml @@ -0,0 +1,9 @@ +- args: + cascade: true + read_only: false + sql: "CREATE OR REPLACE FUNCTION update_conversation_on_message()\nRETURNS TRIGGER + AS $$\nBEGIN\n UPDATE conversations SET updated_at = now() WHERE id = NEW.\"conversationid\";\n + \ RETURN NEW; \nEND;\n$$ language 'plpgsql';\n\nDROP TRIGGER IF EXISTS trigger_update_conversation_on_message + ON messages;\nCREATE TRIGGER trigger_update_conversation_on_message AFTER INSERT + ON messages FOR EACH ROW EXECUTE PROCEDURE update_conversation_on_message();" + type: run_sql