diff --git a/.vscode/launch.json b/.vscode/launch.json index 675e19b5c..ffa7de961 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,7 @@ { "version": "0.2.0", "configurations": [ + { "name": "Chrome", "type": "chrome", @@ -8,6 +9,12 @@ "url": "http://localhost:3000", "webRoot": "${workspaceRoot}/src" + },{ + "name": "Yarn Dev Server", + "type": "node", + "request": "launch", +"runtimeExecutable": "yarn", +"runtimeArgs": ["dev"] } ] } \ No newline at end of file diff --git a/client/src/components/chat-conversation-list/chat-conversation-list.component.jsx b/client/src/components/chat-conversation-list/chat-conversation-list.component.jsx index e7eb370c5..10100a3c8 100644 --- a/client/src/components/chat-conversation-list/chat-conversation-list.component.jsx +++ b/client/src/components/chat-conversation-list/chat-conversation-list.component.jsx @@ -1,12 +1,12 @@ -import { Badge, List, Avatar } from "antd"; +import { Badge, List } from "antd"; import React from "react"; +import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; import { setSelectedConversation } from "../../redux/messaging/messaging.actions"; import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors"; -import { createStructuredSelector } from "reselect"; -import "./chat-conversation-list.styles.scss"; -import { useTranslation } from "react-i18next"; import PhoneFormatter from "../../utils/PhoneFormatter"; +import "./chat-conversation-list.styles.scss"; const mapStateToProps = createStructuredSelector({ selectedConversation: selectSelectedConversation, 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 00c05f76a..75c305320 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,10 +1,9 @@ +import { Space } from "antd"; 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"; -import { Typography, Space } from "antd"; +import ChatTagRoContainer from "../chat-tag-ro/chat-tag-ro.container"; export default function ChatConversationTitle({ conversation }) { - console.log("ChatConversationTitle -> conversation", conversation); return (
@@ -18,7 +17,7 @@ export default function ChatConversationTitle({ conversation }) { )} -
+
{ - if (unreadCount > 0 && !!selectedConversation) { - markConversationRead(); + const handleMarkConversationAsRead = async () => { + if ( + unreadCount > 0 && + !!selectedConversation && + !markingAsReadInProgress + ) { + setMarkingAsReadInProgress(true); + await markConversationRead(); + setMarkingAsReadInProgress(false); } }; diff --git a/client/src/components/chat-messages-list/chat-message-list.component.jsx b/client/src/components/chat-messages-list/chat-message-list.component.jsx index 282c83940..24f954539 100644 --- a/client/src/components/chat-messages-list/chat-message-list.component.jsx +++ b/client/src/components/chat-messages-list/chat-message-list.component.jsx @@ -8,21 +8,21 @@ import { List, } from "react-virtualized"; import "./chat-message-list.styles.scss"; +import { urlencoded } from "body-parser"; export default function ChatMessageListComponent({ messages }) { const virtualizedListRef = useRef(null); const _cache = new CellMeasurerCache({ fixedWidth: true, - minHeight: 25, - defaultHeight: 50, + // minHeight: 50, + defaultHeight: 100, }); - const scrollToBottom = () => { - console.log("Scrolling to", messages.length); - !!virtualizedListRef.current && - virtualizedListRef.current.scrollToRow(messages.length - 1); - + const scrollToBottom = (renderedrows) => { + //console.log("Scrolling to", messages.length); + // !!virtualizedListRef.current && + // virtualizedListRef.current.scrollToRow(messages.length); //TODO Outstanding isue on virtualization: https://github.com/bvaughn/react-virtualized/issues/1179 //Scrolling does not work on this version of React. }; @@ -39,12 +39,11 @@ export default function ChatMessageListComponent({ messages }) { style={style} className={`${ messages[index].isoutbound ? "mine messages" : "yours messages" - }`} - > -
- {messages[index].text} + }`}> +
+ {MessageRender(messages[index])} + {StatusRender(messages[index].status)}
- {StatusRender(messages[index].status)}
)} @@ -52,7 +51,7 @@ export default function ChatMessageListComponent({ messages }) { }; return ( -
+
{({ height, width }) => ( )} @@ -69,12 +71,24 @@ export default function ChatMessageListComponent({ messages }) { ); } +const MessageRender = (message) => { + if (message.image) { + return ( + + + + ); + } else { + return {message.text}; + } +}; + const StatusRender = (status) => { switch (status) { case "sent": - return ; + return ; case "delivered": - return ; + return ; default: return null; } 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 93ac677f2..7e9a1a021 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,8 +1,10 @@ .message-icon { - position: absolute; - bottom: 0rem; - color: seagreen; - border: black; + //position: absolute; + // bottom: 0rem; + color: whitesmoke; + border: #000000; + margin-left: 0.2rem; + margin-right: 0rem; // z-index: 5; } @@ -12,7 +14,7 @@ //border: solid 1px #eee; display: flex; flex-direction: column; - //padding: 10px; + margin: 0.8rem 0rem; } .messages { @@ -26,7 +28,13 @@ padding: 0.25rem 0.8rem; //margin-top: 5px; // margin-bottom: 5px; - display: inline-block; + //display: inline-block; + + .message-img { + max-width: 33%; + object-fit: contain; + } + } .yours { @@ -34,10 +42,11 @@ } .msgmargin { margin-top: 0.1rem; + margin-bottom: 0.1rem; } .yours .message { - margin-right: 25%; + margin-right: 20%; background-color: #eee; position: relative; } diff --git a/client/src/components/chat-popup/chat-popup.styles.scss b/client/src/components/chat-popup/chat-popup.styles.scss index 4b4f36d61..e10e8df18 100644 --- a/client/src/components/chat-popup/chat-popup.styles.scss +++ b/client/src/components/chat-popup/chat-popup.styles.scss @@ -1,6 +1,6 @@ .chat-popup { - width: 40vw; - height: 50vh; + width: 90vw; + height: 95vh; display: flex; flex-direction: column; } @@ -9,3 +9,12 @@ //height: 50vh; flex: 1; } + +@media only screen and (min-width: 992px) { + .chat-popup { + width: 60vw; + height: 55vh; + display: flex; + flex-direction: column; + } +} diff --git a/client/src/components/dashboard-grid/dashboard-grid.component.jsx b/client/src/components/dashboard-grid/dashboard-grid.component.jsx index 084840de1..585187815 100644 --- a/client/src/components/dashboard-grid/dashboard-grid.component.jsx +++ b/client/src/components/dashboard-grid/dashboard-grid.component.jsx @@ -7,12 +7,13 @@ import { useTranslation } from "react-i18next"; import { MdClose } from "react-icons/md"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; -import { UPDATE_DASHBOARD_LAYOUT } from "../../graphql/user.queries"; import { QUERY_DASHBOARD_DETAILS } from "../../graphql/bodyshop.queries"; +import { UPDATE_DASHBOARD_LAYOUT } from "../../graphql/user.queries"; import { selectBodyshop, selectCurrentUser, } from "../../redux/user/user.selectors"; +import AlertComponent from "../alert/alert.component"; import DashboardMonthlyRevenueGraph from "../dashboard-components/monthly-revenue-graph/monthly-revenue-graph.component"; import DashboardProjectedMonthlySales from "../dashboard-components/pojected-monthly-sales/projected-monthly-sales.component"; import DashboardTotalProductionDollars from "../dashboard-components/total-production-dollars/total-production-dollars.component"; @@ -23,6 +24,7 @@ import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component"; // /node_modules/react-resizable/css/styles.css import "./dashboard-grid.styles.css"; import "./dashboard-grid.styles.scss"; + const ResponsiveReactGridLayout = WidthProvider(Responsive); const mapStateToProps = createStructuredSelector({ @@ -91,13 +93,15 @@ export function DashboardGridComponent({ currentUser, bodyshop }) { + disabled={existingLayoutKeys.includes(key)}> {componentList[key].label} ))} ); + console.log("Dashboard Data:", data); + + if (error) return ; return (
@@ -105,13 +109,12 @@ export function DashboardGridComponent({ currentUser, bodyshop }) { + onBreakpointChange={onBreakpointChange}> {state.layout.map((item, index) => { const TheComponent = componentList[item.i].component; return ( @@ -130,8 +133,8 @@ export function DashboardGridComponent({ currentUser, bodyshop }) { onClick={() => handleRemoveComponent(item.i)} /> diff --git a/client/src/graphql/bodyshop.queries.js b/client/src/graphql/bodyshop.queries.js index 6c7c937e6..3762e0cb1 100644 --- a/client/src/graphql/bodyshop.queries.js +++ b/client/src/graphql/bodyshop.queries.js @@ -124,30 +124,27 @@ export const QUERY_STRIPE_ID = gql` export const QUERY_DASHBOARD_DETAILS = gql` query QUERY_DASHBOARD_DETAILS { - query - QUERY_DASHBOARD_DETAILS { - jobs { - id - clm_total - scheduled_completion - date_invoiced - ins_co_nm - } - compJobs: jobs(where: { inproduction: { _eq: true } }) { - id - scheduled_completion - labhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAB" } }) { - aggregate { - sum { - mod_lb_hrs - } + jobs { + id + clm_total + scheduled_completion + date_invoiced + ins_co_nm + } + compJobs: jobs(where: { inproduction: { _eq: true } }) { + id + scheduled_completion + labhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAB" } }) { + aggregate { + sum { + mod_lb_hrs } } - larhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAR" } }) { - aggregate { - sum { - mod_lb_hrs - } + } + larhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAR" } }) { + aggregate { + sum { + mod_lb_hrs } } } diff --git a/client/src/graphql/conversations.queries.js b/client/src/graphql/conversations.queries.js index aa7e5ba05..ecdbc4e5e 100644 --- a/client/src/graphql/conversations.queries.js +++ b/client/src/graphql/conversations.queries.js @@ -33,6 +33,8 @@ export const CONVERSATION_SUBSCRIPTION_BY_PK = gql` status text isoutbound + image + image_path } messages_aggregate( where: { read: { _eq: false }, isoutbound: { _eq: false } } diff --git a/server/sms/receive.js b/server/sms/receive.js index 866bdb889..9810e4d29 100644 --- a/server/sms/receive.js +++ b/server/sms/receive.js @@ -13,7 +13,8 @@ const admin = require("../firebase/firebase-handler").admin; exports.receive = (req, res) => { //Perform request validation - console.log("Twilio Receive Inbound"); + console.log("[SMS Receive] Inbound Twilio Message.", req.body.SmsMessageSid); + console.log("req.body", req.body); if ( !!!req.body || !!!req.body.MessagingServiceSid || @@ -29,7 +30,12 @@ exports.receive = (req, res) => { }) .then((response) => { //TODO Add logic for handling MMS. - let newMessage = { msid: req.body.SmsMessageSid, text: req.body.Body }; + let newMessage = { + msid: req.body.SmsMessageSid, + text: req.body.Body, + image: !!req.body.MediaUrl0, + image_path: req.body.MediaUrl0 || null, + }; if (response.bodyshops[0]) { //Found a bodyshop - should always happen. if (response.bodyshops[0].conversations.length === 0) { @@ -57,7 +63,7 @@ exports.receive = (req, res) => { client .request(queries.INSERT_MESSAGE, { msg: newMessage }) .then((r2) => { - console.log("R2", JSON.stringify(r2)); + res.status(200).send(""); const arrayOfAllUserFcmTokens = r2.insert_messages.returning[0].conversation.bodyshop.associations.map( (a) => a.user.fcmtokens @@ -77,7 +83,7 @@ exports.receive = (req, res) => { }, tokens: uniqueTokens, }; - res.status(200).send(""); + // Send a message to the device corresponding to the provided // registration token. admin @@ -86,8 +92,8 @@ exports.receive = (req, res) => { .then((response) => { // Response is a message ID string. console.log( - "Successfully sent message:", - JSON.stringify(response) + "[SMS Receive] Successfully sent FCM Broadcast.:", + //JSON.stringify(response) ); }) .catch((error) => { @@ -129,3 +135,27 @@ exports.receive = (req, res) => { // "From": "+16049992002", // "ApiVersion": "2010-04-01" // } +// ] req.body { +// [0] ToCountry: 'CA', +// [0] MediaContentType0: 'image/jpeg', +// [0] ToState: 'BC', +// [0] SmsMessageSid: 'MM14fa2851ba26e0dc2b62073f8e7cdf27', +// [0] NumMedia: '1', +// [0] ToCity: 'Vancouver', +// [0] FromZip: '', +// [0] SmsSid: 'MM14fa2851ba26e0dc2b62073f8e7cdf27', +// [0] FromState: 'BC', +// [0] SmsStatus: 'received', +// [0] FromCity: 'VANCOUVER', +// [0] Body: '', +// [0] FromCountry: 'CA', +// [0] To: '+16043301606', +// [0] MessagingServiceSid: 'MG6e259e2add04ffa0d0aa355038670ee1', +// [0] ToZip: '', +// [0] NumSegments: '1', +// [0] MessageSid: 'MM14fa2851ba26e0dc2b62073f8e7cdf27', +// [0] AccountSid: 'AC6c09d337d6b9c68ab6488c2052bd457c', +// [0] From: '+16049992002', +// [0] MediaUrl0: 'https://api.twilio.com/2010-04-01/Accounts/AC6c09d337d6b9c68ab6488c2052bd457c/Messages/MM14fa2851ba26e0dc2b62073f8e7cdf27/Media/MEf129dd37979852f395eb29ffb126e19e', +// [0] ApiVersion: '2010-04-01' +// [0] } diff --git a/server/sms/send.js b/server/sms/send.js index cc3841864..3db67b236 100644 --- a/server/sms/send.js +++ b/server/sms/send.js @@ -36,7 +36,7 @@ exports.send = (req, res) => { gqlClient .request(queries.INSERT_MESSAGE, { msg: newMessage }) .then((r2) => { - console.log("Responding GQL Message ID", JSON.stringify(r2)); + //console.log("Responding GQL Message ID", JSON.stringify(r2)); res.sendStatus(200); }) .catch((e2) => { diff --git a/server/sms/status.js b/server/sms/status.js index 3822c6d93..3d56c468e 100644 --- a/server/sms/status.js +++ b/server/sms/status.js @@ -18,7 +18,7 @@ exports.status = (req, res) => { fields: { status: SmsStatus }, }) .then((response) => { - console.log("Message Updated"); + console.log("Message Updated", JSON.stringify(response)); }) .catch((error) => { console.log("Error updating message status", error);