From 0d5f5167ef3138ef9b4b37b71e30cc75be938cdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9rgio=20Salgado?= Date: Fri, 4 Feb 2022 19:39:35 +0000 Subject: [PATCH] feat: change custom SMS instances to SMS notices and all its interfaces --- lib/constants.js | 4 +- lib/custom-sms.js | 41 ------- .../graphql/resolvers/sms.resolver.js | 10 +- lib/new-admin/graphql/types/sms.type.js | 18 +-- lib/sms-notices.js | 56 +++++++++ lib/sms.js | 2 +- ...3996603839-change-custom-sms-to-notices.js | 21 ++++ .../CustomSMSModal.js | 37 ++---- .../CustomSMS.js => SMSNotices/SMSNotices.js} | 109 ++++++++---------- .../SMSNotices.styles.js} | 0 .../src/routing/lamassu.routes.js | 2 +- new-lamassu-admin/src/routing/pazuz.routes.js | 2 +- 12 files changed, 153 insertions(+), 149 deletions(-) delete mode 100644 lib/custom-sms.js create mode 100644 lib/sms-notices.js create mode 100644 migrations/1643996603839-change-custom-sms-to-notices.js rename new-lamassu-admin/src/pages/OperatorInfo/{CustomSMS => SMSNotices}/CustomSMSModal.js (80%) rename new-lamassu-admin/src/pages/OperatorInfo/{CustomSMS/CustomSMS.js => SMSNotices/SMSNotices.js} (50%) rename new-lamassu-admin/src/pages/OperatorInfo/{CustomSMS/CustomSMS.styles.js => SMSNotices/SMSNotices.styles.js} (100%) diff --git a/lib/constants.js b/lib/constants.js index 1efcf1d7..c4bc2fbc 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -20,6 +20,7 @@ const MANUAL = 'manual' const CASH_OUT_DISPENSE_READY = 'cash_out_dispense_ready' const CONFIRMATION_CODE = 'sms_code' +const RECEIPT = 'sms_receipt' const WALLET_SCORE_THRESHOLD = 9 @@ -37,5 +38,6 @@ module.exports = { CONFIRMATION_CODE, CASH_OUT_MINIMUM_AMOUNT_OF_CASSETTES, CASH_OUT_MAXIMUM_AMOUNT_OF_CASSETTES, - WALLET_SCORE_THRESHOLD + WALLET_SCORE_THRESHOLD, + RECEIPT } diff --git a/lib/custom-sms.js b/lib/custom-sms.js deleted file mode 100644 index 8cb8546a..00000000 --- a/lib/custom-sms.js +++ /dev/null @@ -1,41 +0,0 @@ -const _ = require('lodash/fp') -const uuid = require('uuid') -const db = require('./db') - -const getCustomMessages = () => { - const sql = `SELECT * FROM custom_messages ORDER BY created` - return db.any(sql).then(res => _.map( - it => ({ - id: it.id, - event: _.camelCase(it.event), - message: it.message - }), res)) -} - -const createCustomMessage = (event, message) => { - const sql = `INSERT INTO custom_messages (id, event, message) VALUES ($1, $2, $3)` - return db.none(sql, [uuid.v4(), _.snakeCase(event), message]) -} - -const editCustomMessage = (id, event, message) => { - const sql = `UPDATE custom_messages SET event=$2, message=$3 WHERE id=$1` - return db.none(sql, [id, _.snakeCase(event), message]) -} - -const deleteCustomMessage = id => { - const sql = `DELETE FROM custom_messages WHERE id=$1` - return db.none(sql, [id]) -} - -const getCustomMessage = event => { - const sql = `SELECT * FROM custom_messages WHERE event=$1 LIMIT 1` - return db.oneOrNone(sql, [event]) -} - -module.exports = { - getCustomMessages, - createCustomMessage, - editCustomMessage, - deleteCustomMessage, - getCustomMessage -} diff --git a/lib/new-admin/graphql/resolvers/sms.resolver.js b/lib/new-admin/graphql/resolvers/sms.resolver.js index f159c8c4..3709395d 100644 --- a/lib/new-admin/graphql/resolvers/sms.resolver.js +++ b/lib/new-admin/graphql/resolvers/sms.resolver.js @@ -1,13 +1,13 @@ -const customSms = require('../../../custom-sms') +const customSms = require('../../../sms-notices') const resolvers = { Query: { - customMessages: () => customSms.getCustomMessages() + SMSNotices: () => customSms.getSMSNotices() }, Mutation: { - createCustomMessage: (...[, { event, message }]) => customSms.createCustomMessage(event, message), - editCustomMessage: (...[, { id, event, message }]) => customSms.editCustomMessage(id, event, message), - deleteCustomMessage: (...[, { id }]) => customSms.deleteCustomMessage(id) + editSMSNotice: (...[, { id, event, message }]) => customSms.editSMSNotice(id, event, message), + enableSMSNotice: (...[, { id }]) => customSms.enableSMSNotice(id), + disableSMSNotice: (...[, { id }]) => customSms.disableSMSNotice(id) } } diff --git a/lib/new-admin/graphql/types/sms.type.js b/lib/new-admin/graphql/types/sms.type.js index a86947b7..b67ec1fa 100644 --- a/lib/new-admin/graphql/types/sms.type.js +++ b/lib/new-admin/graphql/types/sms.type.js @@ -1,25 +1,29 @@ const { gql } = require('apollo-server-express') const typeDef = gql` - type CustomMessage { + type SMSNotice { id: ID! - event: CustomMessageEvent! + event: SMSNoticeEvent! message: String! + messageName: String! + enabled: Boolean! + allowToggle: Boolean! } - enum CustomMessageEvent { + enum SMSNoticeEvent { smsCode cashOutDispenseReady + smsReceipt } type Query { - customMessages: [CustomMessage] @auth + SMSNotices: [SMSNotice] @auth } type Mutation { - createCustomMessage(event: CustomMessageEvent!, message: String!): CustomMessage @auth - editCustomMessage(id: ID!, event: CustomMessageEvent!, message: String!): CustomMessage @auth - deleteCustomMessage(id: ID!): CustomMessage @auth + editSMSNotice(id: ID!, event: SMSNoticeEvent!, message: String!): SMSNotice @auth + enableSMSNotice(id: ID!): SMSNotice @auth + disableSMSNotice(id: ID!): SMSNotice @auth } ` diff --git a/lib/sms-notices.js b/lib/sms-notices.js new file mode 100644 index 00000000..f2235069 --- /dev/null +++ b/lib/sms-notices.js @@ -0,0 +1,56 @@ +const _ = require('lodash/fp') +const uuid = require('uuid') +const db = require('./db') + +const getSMSNotices = () => { + const sql = `SELECT * FROM sms_notices ORDER BY created` + return db.any(sql).then(res => _.map( + it => ({ + id: it.id, + event: _.camelCase(it.event), + message: it.message, + messageName: it.message_name, + enabled: it.enabled, + allowToggle: it.allow_toggle + }), res)) +} + +const createSMSNotice = (event, messageName, message, enabled, allowToggle) => { + const sql = `INSERT INTO sms_notices (id, event, message_name, message${enabled ? `, enabled`: ``}${allowToggle ? `, allowToggle`: ``}) VALUES ($1, $2, $3, $4${enabled ? `, $5`: ``}${allowToggle ? `, $6`: ``})` + return db.none(sql, [uuid.v4(), _.snakeCase(event), messageName, message, enabled, allowToggle]) +} + +const editSMSNotice = (id, event, message) => { + const sql = `UPDATE sms_notices SET event=$2, message=$3 WHERE id=$1` + return db.none(sql, [id, _.snakeCase(event), message]) +} + +const deleteSMSNotice = id => { + const sql = `DELETE FROM sms_notices WHERE id=$1` + return db.none(sql, [id]) +} + +const getSMSNotice = event => { + const sql = `SELECT * FROM sms_notices WHERE event=$1 LIMIT 1` + return db.oneOrNone(sql, [event]) +} + +const enableSMSNotice = id => { + const sql = `UPDATE sms_notices SET enabled = true WHERE id=$1 LIMIT 1` + return db.oneOrNone(sql, [id]) +} + +const disableSMSNotice = id => { + const sql = `UPDATE sms_notices SET enabled = false WHERE id=$1 LIMIT 1` + return db.oneOrNone(sql, [id]) +} + +module.exports = { + getSMSNotices, + createSMSNotice, + editSMSNotice, + deleteSMSNotice, + getSMSNotice, + enableSMSNotice, + disableSMSNotice +} diff --git a/lib/sms.js b/lib/sms.js index 71b691c2..f8d1f18d 100644 --- a/lib/sms.js +++ b/lib/sms.js @@ -3,7 +3,7 @@ const argv = require('minimist')(process.argv.slice(2)) const { utils: coinUtils } = require('lamassu-coins') const _ = require('lodash/fp') -const customSms = require('./custom-sms') +const customSms = require('./sms-notices') const getDefaultMessageContent = content => ({ smsCode: `Your cryptomat code: ${content.code}`, diff --git a/migrations/1643996603839-change-custom-sms-to-notices.js b/migrations/1643996603839-change-custom-sms-to-notices.js new file mode 100644 index 00000000..c2d9ffd3 --- /dev/null +++ b/migrations/1643996603839-change-custom-sms-to-notices.js @@ -0,0 +1,21 @@ +var db = require('./db') +var smsNotices = require('../lib/sms-notices') + +exports.up = function (next) { + var sql = [ + `ALTER TABLE custom_messages RENAME TO sms_notices`, + `ALTER TYPE custom_message_event RENAME TO sms_notice_event`, + `ALTER TYPE sms_notice_event ADD VALUE 'sms_receipt'`, + `ALTER TABLE sms_notices ADD COLUMN message_name TEXT UNIQUE NOT NULL`, + `ALTER TABLE sms_notices ADD COLUMN enabled BOOLEAN NOT NULL DEFAULT true` + `ALTER TABLE sms_notices ADD COLUMN allow_toggle BOOLEAN NOT NULL DEFAULT true` + ] + + db.multi(sql, next) + .then(() => smsNotices.createSMSNotice('sms_code', 'SMS confirmation code', 'Your cryptomat code: #code', true, false)) + .then(() => smsNotices.createSMSNotice('cash_out_dispense_ready', 'Cash is ready', 'Your cash is waiting! Go to the Cryptomat and press Redeem within 24 hours. [#timestamp]', true, false)) +} + +exports.down = function (next) { + next() +} diff --git a/new-lamassu-admin/src/pages/OperatorInfo/CustomSMS/CustomSMSModal.js b/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/CustomSMSModal.js similarity index 80% rename from new-lamassu-admin/src/pages/OperatorInfo/CustomSMS/CustomSMSModal.js rename to new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/CustomSMSModal.js index 7b993021..cf76bb5d 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/CustomSMS/CustomSMSModal.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/CustomSMSModal.js @@ -1,15 +1,15 @@ import { makeStyles } from '@material-ui/core' import { Form, Formik, Field } from 'formik' import * as R from 'ramda' -import React, { useState } from 'react' +import React from 'react' import * as Yup from 'yup' import ErrorMessage from 'src/components/ErrorMessage' import Modal from 'src/components/Modal' import { Button } from 'src/components/buttons' -import { Autocomplete, TextInput } from 'src/components/inputs/formik' +import { TextInput } from 'src/components/inputs/formik' -import styles from './CustomSMS.styles' +import styles from './SMSNotices.styles' const useStyles = makeStyles(styles) @@ -58,18 +58,9 @@ const prefill = { } } -const CustomSMSModal = ({ - showModal, - onClose, - sms, - eventOptions, - creationError, - submit -}) => { +const CustomSMSModal = ({ showModal, onClose, sms, creationError, submit }) => { const classes = useStyles() - const [selectedEvent, setSelectedEvent] = useState(sms?.event) - const initialValues = { event: !R.isNil(sms) ? sms.event : '', message: !R.isNil(sms) ? sms.message : '' @@ -78,7 +69,7 @@ const CustomSMSModal = ({ const validationSchema = Yup.object().shape({ event: Yup.string().required('An event is required!'), message: - prefill[selectedEvent]?.validator ?? + prefill[sms?.event]?.validator ?? Yup.string() .required('The message content is required!') .trim() @@ -106,7 +97,7 @@ const CustomSMSModal = ({ <> {showModal && ( {({ values, errors, touched }) => ( -
- + - {!R.isNil(sms) ? `Confirm` : `Create SMS`} + Confirm diff --git a/new-lamassu-admin/src/pages/OperatorInfo/CustomSMS/CustomSMS.js b/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js similarity index 50% rename from new-lamassu-admin/src/pages/OperatorInfo/CustomSMS/CustomSMS.js rename to new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js index b1d3dac0..edbc8ec3 100644 --- a/new-lamassu-admin/src/pages/OperatorInfo/CustomSMS/CustomSMS.js +++ b/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.js @@ -1,65 +1,59 @@ import { useQuery, useMutation } from '@apollo/react-hooks' -import { makeStyles, Box } from '@material-ui/core' +import { makeStyles } from '@material-ui/core' import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' import { DeleteDialog } from 'src/components/DeleteDialog' -import { Link, IconButton } from 'src/components/buttons' +import { IconButton } from 'src/components/buttons' +import { Switch } from 'src/components/inputs' import DataTable from 'src/components/tables/DataTable' import { H4 } from 'src/components/typography' -import { ReactComponent as DeleteIcon } from 'src/styling/icons/action/delete/enabled.svg' import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg' -import styles from './CustomSMS.styles' import CustomSMSModal from './CustomSMSModal' +import styles from './SMSNotices.styles' const useStyles = makeStyles(styles) -const GET_CUSTOM_MESSAGES = gql` - query customMessages { - customMessages { +const GET_SMS_NOTICES = gql` + query SMSNotices { + SMSNotices { id event message + messageName + enabled + allowToggle } } ` -const CREATE_CUSTOM_MESSAGE = gql` - mutation createCustomMessage($event: CustomMessageEvent!, $message: String!) { - createCustomMessage(event: $event, message: $message) { +const EDIT_SMS_NOTICE = gql` + mutation editSMSNotice($id: ID!, $event: SMSNoticeEvent!, $message: String!) { + editSMSNotice(id: $id, event: $event, message: $message) { id } } ` -const EDIT_CUSTOM_MESSAGE = gql` - mutation editCustomMessage( - $id: ID! - $event: CustomMessageEvent! - $message: String! - ) { - editCustomMessage(id: $id, event: $event, message: $message) { +const ENABLE_SMS_NOTICE = gql` + mutation enableSMSNotice($id: ID!) { + enableSMSNotice(id: $id) { id } } ` -const DELETE_CUSTOM_MESSAGE = gql` - mutation deleteCustomMessage($id: ID!) { - deleteCustomMessage(id: $id) { +const DISABLE_SMS_NOTICE = gql` + mutation disableSMSNotice($id: ID!) { + disableSMSNotice(id: $id) { id } } ` -const EVENT_OPTIONS = [ - { code: 'smsCode', display: 'On SMS confirmation code' }, - { code: 'cashOutDispenseReady', display: 'Cash out dispense ready' } -] - -const CustomSMS = () => { +const SMSNotices = () => { const classes = useStyles() const [deleteDialog, setDeleteDialog] = useState(false) @@ -68,22 +62,22 @@ const CustomSMS = () => { const [errorMsg, setErrorMsg] = useState('') const { data: messagesData, loading: messagesLoading } = useQuery( - GET_CUSTOM_MESSAGES + GET_SMS_NOTICES ) - const [createMessage] = useMutation(CREATE_CUSTOM_MESSAGE, { + const [editMessage] = useMutation(EDIT_SMS_NOTICE, { onError: ({ msg }) => setErrorMsg(msg), - refetchQueries: () => ['customMessages'] + refetchQueries: () => ['SMSNotices'] }) - const [editMessage] = useMutation(EDIT_CUSTOM_MESSAGE, { + const [enableMessage] = useMutation(ENABLE_SMS_NOTICE, { onError: ({ msg }) => setErrorMsg(msg), - refetchQueries: () => ['customMessages'] + refetchQueries: () => ['SMSNotices'] }) - const [deleteMessage] = useMutation(DELETE_CUSTOM_MESSAGE, { + const [disableMessage] = useMutation(DISABLE_SMS_NOTICE, { onError: ({ msg }) => setErrorMsg(msg), - refetchQueries: () => ['customMessages'] + refetchQueries: () => ['SMSNotices'] }) const loading = messagesLoading @@ -94,19 +88,15 @@ const CustomSMS = () => { setDeleteDialog(false) } - const handleOpen = () => { - setErrorMsg('') - setShowModal(true) - } + console.log(messagesData) const elements = [ { - header: 'Event', - width: 600, + header: 'Message name', + width: 500, size: 'sm', textAlign: 'left', - view: it => - R.find(ite => R.propEq('event', ite.code, it), EVENT_OPTIONS).display + view: it => R.prop('messageName', it) }, { header: 'Edit', @@ -124,18 +114,20 @@ const CustomSMS = () => { ) }, { - header: 'Delete', + header: 'Enable', width: 100, size: 'sm', textAlign: 'center', view: it => ( - { - setSelectedSMS(it) - setDeleteDialog(true) - }}> - - + it.enabled + ? disableMessage({ variables: { id: it.id } }) + : enableMessage({ variables: { id: it.id } }) + }} + checked={it.enabled} + /> ) } ] @@ -143,21 +135,15 @@ const CustomSMS = () => { return ( <>
-

Custom SMS message

- - handleOpen()}> - Add custom SMS - - +

SMS Notices

{showModal && ( )} { }} onConfirmed={() => { handleClose() - deleteMessage({ - variables: { - id: selectedSMS.id - } - }) }} errorMessage={errorMsg} /> ) } -export default CustomSMS +export default SMSNotices diff --git a/new-lamassu-admin/src/pages/OperatorInfo/CustomSMS/CustomSMS.styles.js b/new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.styles.js similarity index 100% rename from new-lamassu-admin/src/pages/OperatorInfo/CustomSMS/CustomSMS.styles.js rename to new-lamassu-admin/src/pages/OperatorInfo/SMSNotices/SMSNotices.styles.js diff --git a/new-lamassu-admin/src/routing/lamassu.routes.js b/new-lamassu-admin/src/routing/lamassu.routes.js index e647c65b..7573c955 100644 --- a/new-lamassu-admin/src/routing/lamassu.routes.js +++ b/new-lamassu-admin/src/routing/lamassu.routes.js @@ -16,8 +16,8 @@ import MachineStatus from 'src/pages/Maintenance/MachineStatus' import Notifications from 'src/pages/Notifications/Notifications' import CoinAtmRadar from 'src/pages/OperatorInfo/CoinATMRadar' import ContactInfo from 'src/pages/OperatorInfo/ContactInfo' -import CustomSMS from 'src/pages/OperatorInfo/CustomSMS/CustomSMS' import ReceiptPrinting from 'src/pages/OperatorInfo/ReceiptPrinting' +import CustomSMS from 'src/pages/OperatorInfo/SMSNotices/SMSNotices' import TermsConditions from 'src/pages/OperatorInfo/TermsConditions' import ServerLogs from 'src/pages/ServerLogs' import Services from 'src/pages/Services/Services' diff --git a/new-lamassu-admin/src/routing/pazuz.routes.js b/new-lamassu-admin/src/routing/pazuz.routes.js index 153d0205..301c8fa9 100644 --- a/new-lamassu-admin/src/routing/pazuz.routes.js +++ b/new-lamassu-admin/src/routing/pazuz.routes.js @@ -19,8 +19,8 @@ import MachineStatus from 'src/pages/Maintenance/MachineStatus' import Notifications from 'src/pages/Notifications/Notifications' import CoinAtmRadar from 'src/pages/OperatorInfo/CoinATMRadar' import ContactInfo from 'src/pages/OperatorInfo/ContactInfo' -import CustomSMS from 'src/pages/OperatorInfo/CustomSMS/CustomSMS' import ReceiptPrinting from 'src/pages/OperatorInfo/ReceiptPrinting' +import CustomSMS from 'src/pages/OperatorInfo/SMSNotices/SMSNotices' import TermsConditions from 'src/pages/OperatorInfo/TermsConditions' import ServerLogs from 'src/pages/ServerLogs' import Services from 'src/pages/Services/Services'