From 636e979fd0342fc793369e60fafe8033c76e27e5 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 1 May 2020 12:32:40 -0700 Subject: [PATCH] Added notification generation on SMS. Added FCM Token saving on login. --- client/public/firebase-messaging-sw.js | 8 +- client/src/App/App.container.jsx | 28 +- .../fcm-notification.component.jsx | 60 + client/src/graphql/user.queries.js | 16 +- .../pages/manage/manage.page.component.jsx | 3 +- .../down.yaml | 5 + .../up.yaml | 5 + .../down.yaml | 21 + .../up.yaml | 22 + .../down.yaml | 23 + .../up.yaml | 22 + .../down.yaml | 22 + .../up.yaml | 24 + .../down.yaml | 25 + .../up.yaml | 24 + .../down.yaml | 5 + .../up.yaml | 5 + hasura/migrations/metadata.yaml | 3463 +++++++++++++++++ server/firebase/firebase-handler.js | 8 +- server/graphql-client/queries.js | 14 +- server/sms/receive.js | 52 +- 21 files changed, 3810 insertions(+), 45 deletions(-) create mode 100644 client/src/components/fcm-notification/fcm-notification.component.jsx create mode 100644 hasura/migrations/1588355454260_alter_table_public_users_add_column_fcmtokens/down.yaml create mode 100644 hasura/migrations/1588355454260_alter_table_public_users_add_column_fcmtokens/up.yaml create mode 100644 hasura/migrations/1588355462630_update_permission_user_public_table_users/down.yaml create mode 100644 hasura/migrations/1588355462630_update_permission_user_public_table_users/up.yaml create mode 100644 hasura/migrations/1588355471991_update_permission_user_public_table_users/down.yaml create mode 100644 hasura/migrations/1588355471991_update_permission_user_public_table_users/up.yaml create mode 100644 hasura/migrations/1588355478259_update_permission_user_public_table_users/down.yaml create mode 100644 hasura/migrations/1588355478259_update_permission_user_public_table_users/up.yaml create mode 100644 hasura/migrations/1588355488534_update_permission_user_public_table_users/down.yaml create mode 100644 hasura/migrations/1588355488534_update_permission_user_public_table_users/up.yaml create mode 100644 hasura/migrations/1588358447309_alter_table_public_users_alter_column_fcmtokens/down.yaml create mode 100644 hasura/migrations/1588358447309_alter_table_public_users_alter_column_fcmtokens/up.yaml create mode 100644 hasura/migrations/metadata.yaml diff --git a/client/public/firebase-messaging-sw.js b/client/public/firebase-messaging-sw.js index de6f9e9a2..cf1e483fc 100644 --- a/client/public/firebase-messaging-sw.js +++ b/client/public/firebase-messaging-sw.js @@ -43,7 +43,7 @@ self.addEventListener("notificationclick", function (event) { console.log("SW notificationclick", event); }); -self.addEventListener("message", (message) => { - console.log("Push from SW", message); -// registration.showNotification("Push from SW" + JSON.stringify(message.data)); -}); +// self.addEventListener("message", (message) => { +// console.log("Push from SW", message); +// // registration.showNotification("Push from SW" + JSON.stringify(message.data)); +// }); diff --git a/client/src/App/App.container.jsx b/client/src/App/App.container.jsx index 7ea2bd371..dfdd81078 100644 --- a/client/src/App/App.container.jsx +++ b/client/src/App/App.container.jsx @@ -9,13 +9,12 @@ import apolloLogger from "apollo-link-logger"; import { RetryLink } from "apollo-link-retry"; import { WebSocketLink } from "apollo-link-ws"; import { getMainDefinition } from "apollo-utilities"; +import LogRocket from "logrocket"; import React, { Component } from "react"; import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component"; -import { auth, messaging } from "../firebase/firebase.utils"; +import { auth } from "../firebase/firebase.utils"; import errorLink from "../graphql/apollo-error-handling"; import App from "./App"; -import LogRocket from "logrocket"; -import { notification } from "antd"; if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp"); @@ -117,29 +116,6 @@ export default class AppContainer extends Component { this.state = { client }; } - async componentDidMount() { - messaging - .requestPermission() - .then(async function () { - const token = await messaging.getToken(); - console.log("messaging -> token", token); - }) - .catch(function (err) { - console.log("Unable to get permission to notify.", err); - }); - navigator.serviceWorker.addEventListener("message", (message) => { - console.log("Comp Did Mount", message); - notification["info"]({ message: JSON.stringify(message.data) }); - navigator.serviceWorker - .getRegistration() - .then((registration) => - registration.showNotification( - "Comp Did" + JSON.stringify(message.data) - ) - ); - }); - } - render() { const { client } = this.state; diff --git a/client/src/components/fcm-notification/fcm-notification.component.jsx b/client/src/components/fcm-notification/fcm-notification.component.jsx new file mode 100644 index 000000000..9234b7427 --- /dev/null +++ b/client/src/components/fcm-notification/fcm-notification.component.jsx @@ -0,0 +1,60 @@ +import { notification } from "antd"; +import React, { Component } from "react"; +import { messaging } from "../../firebase/firebase.utils"; +import { withApollo } from "react-apollo"; +import { UPDATE_FCM_TOKEN } from "../../graphql/user.queries"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { selectCurrentUser } from "../../redux/user/user.selectors"; +const mapStateToProps = createStructuredSelector({ + currentUser: selectCurrentUser, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); + +class FcmNotificationComponent extends Component { + async componentDidMount() { + const { client, currentUser } = this.props; + messaging + .requestPermission() + .then(async function () { + const token = await messaging.getToken(); + + client.mutate({ + mutation: UPDATE_FCM_TOKEN, + variables: { authEmail: currentUser.email, token: { [token]: true } }, + }); + }) + .catch(function (err) { + console.log("Unable to get permission to notify.", err); + }); + navigator.serviceWorker.addEventListener("message", (message) => { + const { payload } = message.data.firebaseMessaging; + // notification["info"]({ message: JSON.stringify(payload) }); + + navigator.serviceWorker.getRegistration().then((registration) => + registration.showNotification(payload.notification.title, { + body: payload.notification.body, + icon: "logo240.png", + badge: "logo240.png", + actions: [ + { + action: "respond", + title: "Respond", + }, + ], + }) + ); + }); + } + + render() { + return
; + } +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(withApollo(FcmNotificationComponent)); diff --git a/client/src/graphql/user.queries.js b/client/src/graphql/user.queries.js index 8b697ec52..47ccbb661 100644 --- a/client/src/graphql/user.queries.js +++ b/client/src/graphql/user.queries.js @@ -1,7 +1,7 @@ import { gql } from "apollo-boost"; export const UPSERT_USER = gql` - mutation upsert_user($authEmail: String!, $authToken: String!) { + mutation UPSERT_USER($authEmail: String!, $authToken: String!) { insert_users( objects: [{ email: $authEmail, authid: $authToken }] on_conflict: { constraint: users_pkey, update_columns: [authid] } @@ -12,3 +12,17 @@ export const UPSERT_USER = gql` } } `; + +export const UPDATE_FCM_TOKEN = gql` + mutation UPDATE_FCM_TOKEN($authEmail: String!, $token: jsonb!) { + update_users( + where: { email: { _eq: $authEmail } } + _append: { fcmtokens: $token } + ) { + affected_rows + returning { + fcmtokens + } + } + } +`; diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx index dfde28fad..10b1e07d0 100644 --- a/client/src/pages/manage/manage.page.component.jsx +++ b/client/src/pages/manage/manage.page.component.jsx @@ -11,7 +11,7 @@ import "./manage.page.styles.scss"; import BreadCrumbs from "../../components/breadcrumbs/breadcrumbs.component"; import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container"; import ChatAffixContainer from "../../components/chat-affix/chat-affix.container"; - +import FcmNotification from "../../components/fcm-notification/fcm-notification.component"; const ManageRootPage = lazy(() => import("../manage-root/manage-root.page.container") ); @@ -100,6 +100,7 @@ export default function Manage({ match }) { + { console.log("Firebase Send."); // const { ids } = req.body; @@ -19,11 +21,11 @@ exports.sendNotification = (req, res) => { //Dev var registrationToken = - "dwsrcoeaIpwEmSzrVkE-_V:APA91bFurr0yCN-yXcaNrJvn8_f47I4vb4avxeS0NR5SCBPNADFB-gC79Hdmj7wqPccPmZCx0NzA_Dqi1lLYegpN-tFvANaK9I00oOSsFnOxv6KNZDLW0WguwFA0vQN8X50BaGuLTQqM"; + "fqIWg8ENDFyrRrMWJ1sItR:APA91bHirdZ05Zo66flMlvala97SMXoiQGwP4oCvMwd-vVrSauD_WoNim3kXHGqyP-bzENjkXwA5icyUAReFbeHn6dIaPcbpcsXuY73-eJAXvZiu1gIsrd1BOsnj3dEMT7Q4F6mTPth1"; var message = { + notification: { title: "The Title", body: "The Body" }, data: { - title: "850", - body: "2:45", + jobid: "1234", }, token: registrationToken, }; diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index 5392db6a3..b23cc6d56 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -14,12 +14,20 @@ query FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID( exports.INSERT_MESSAGE = ` mutation INSERT_MESSAGE($msg: [messages_insert_input!]!) { - insert_messages(objects: $msg) { - returning { - id + insert_messages(objects: $msg) { + returning { + conversation { + bodyshop { + associations(where: {active: {_eq: true}}) { + user { + fcmtokens + } + } + } } } } +} `; exports.UPDATE_MESSAGE_STATUS = ` diff --git a/server/sms/receive.js b/server/sms/receive.js index 7f5f3c733..9aad4fca8 100644 --- a/server/sms/receive.js +++ b/server/sms/receive.js @@ -2,9 +2,11 @@ require("dotenv").config(); const client = require("../graphql-client/graphql-client").client; const queries = require("../graphql-client/queries"); const phone = require("phone"); +const admin = require("../firebase/firebase-handler").admin; exports.receive = (req, res) => { //Perform request validation + console.log("Twilio Receive Inbound"); if ( !!!req.body || !!!req.body.MessagingServiceSid || @@ -16,9 +18,9 @@ exports.receive = (req, res) => { client .request(queries.FIND_BODYSHOP_BY_MESSAGING_SERVICE_SID, { mssid: req.body.MessagingServiceSid, - phone: phone(req.body.From)[0] + phone: phone(req.body.From)[0], }) - .then(response => { + .then((response) => { //TODO Add logic for handling MMS. let newMessage = { msid: req.body.SmsMessageSid, text: req.body.Body }; if (response.bodyshops[0]) { @@ -29,8 +31,8 @@ exports.receive = (req, res) => { newMessage.conversation = { data: { bodyshopid: response.bodyshops[0].id, - phone_num: phone(req.body.From)[0] - } + phone_num: phone(req.body.From)[0], + }, }; } else if (response.bodyshops[0].conversations.length === 1) { //Just add it to the conversation @@ -47,16 +49,52 @@ exports.receive = (req, res) => { client .request(queries.INSERT_MESSAGE, { msg: newMessage }) - .then(r2 => { + .then((r2) => { + console.log("R2", JSON.stringify(r2)); + + const arrayOfAllUserFcmTokens = r2.insert_messages.returning[0].conversation.bodyshop.associations.map( + (a) => a.user.fcmtokens + ); + const allTokens = []; + arrayOfAllUserFcmTokens.map((i) => + Object.keys(i).map((k) => allTokens.push(k)) + ); + const uniqueTokens = [...new Set(allTokens)]; + console.log("exports.receive -> uniqueTokens", uniqueTokens); + + var message = { + notification: { + title: `New SMS From ${phone(req.body.From)[0]}`, + body: req.body.Body, + }, + data: { + jobid: "1234", + }, + tokens: uniqueTokens, + }; + + // Send a message to the device corresponding to the provided + // registration token. + admin + .messaging() + .sendMulticast(message) + .then((response) => { + // Response is a message ID string. + console.log("Successfully sent message:", response); + }) + .catch((error) => { + console.log("Error sending message:", error); + }); + res.status(200).end(); }) - .catch(e2 => { + .catch((e2) => { console.log("e2", e2); res.status(500).json(e2); }); } }) - .catch(e1 => { + .catch((e1) => { console.log("e1", e1); res.status(500).json(e1); });