diff --git a/new-lamassu-admin/src/pages/Notifications/Notifications.js b/new-lamassu-admin/src/pages/Notifications/Notifications.js index df3dfbcc..b79eb9a7 100644 --- a/new-lamassu-admin/src/pages/Notifications/Notifications.js +++ b/new-lamassu-admin/src/pages/Notifications/Notifications.js @@ -3,10 +3,15 @@ import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' +import Modal from 'src/components/Modal' import TitleSection from 'src/components/layout/TitleSection' +import { P } from 'src/components/typography' +import FormRenderer from 'src/pages/Services/FormRenderer' +import twilioSchema from 'src/pages/Services/schemas/twilio' import { fromNamespace, toNamespace, namespaces } from 'src/utils/config' import Section from '../../components/layout/Section' +import mailgunSchema from '../Services/schemas/mailgun' import NotificationsCtx from './NotificationsContext' import CryptoBalanceAlerts from './sections/CryptoBalanceAlerts' @@ -28,6 +33,7 @@ const GET_INFO = gql` code display } + accounts } ` @@ -37,6 +43,12 @@ const SAVE_CONFIG = gql` } ` +const SAVE_ACCOUNT = gql` + mutation Save($accounts: JSONObject) { + saveAccounts(accounts: $accounts) + } +` + const FIELDS_WIDTH = 130 const Notifications = ({ @@ -52,6 +64,8 @@ const Notifications = ({ const [section, setSection] = useState(null) const [error, setError] = useState(null) const [editingKey, setEditingKey] = useState(null) + const [smsSetupPopup, setSmsSetupPopup] = useState(false) + const [emailSetupPopup, setEmailSetupPopup] = useState(false) const { data, loading } = useQuery(GET_INFO) @@ -61,9 +75,20 @@ const Notifications = ({ onError: error => setError(error) }) + const [saveAccount] = useMutation(SAVE_ACCOUNT, { + onCompleted: () => { + setSmsSetupPopup(false) + setEmailSetupPopup(false) + }, + refetchQueries: ['getData'], + onError: error => setError(error) + }) + const config = fromNamespace(SCREEN_KEY)(data?.config) const machines = data?.machines const cryptoCurrencies = data?.cryptoCurrencies + const twilioAvailable = R.has('twilio', data?.accounts || {}) + const mailgunAvailable = R.has('mailgun', data?.accounts || {}) const currency = R.path(['fiatCurrency'])( fromNamespace(namespaces.LOCALE)(data?.config) @@ -83,6 +108,20 @@ const Notifications = ({ setEditingKey(state ? key : null) } + const twilioSave = it => { + setError(null) + return saveAccount({ + variables: { accounts: { twilio: it } } + }).then(() => R.compose(save(null), toNamespace('sms'))({ active: true })) + } + + const mailgunSave = it => { + setError(null) + return saveAccount({ + variables: { accounts: { mailgun: it } } + }).then(() => R.compose(save(null), toNamespace('email'))({ active: true })) + } + const isEditing = key => editingKey === key const isDisabled = key => editingKey && editingKey !== key @@ -97,50 +136,92 @@ const Notifications = ({ setEditing, setSection, machines, - cryptoCurrencies + cryptoCurrencies, + twilioAvailable, + setSmsSetupPopup, + mailgunAvailable, + setEmailSetupPopup } return ( !loading && ( - - {displayTitle && } - {displaySetup && ( -
- -
+ <> + + {displayTitle && } + {displaySetup && ( +
+ +
+ )} + {displayTransactionAlerts && ( +
+ +
+ )} + {displayFiatAlerts && ( +
+ + {displayOverrides && ( + + )} +
+ )} + {displayCryptoAlerts && ( +
+ + {displayOverrides && ( + + )} +
+ )} +
+ {smsSetupPopup && ( + setSmsSetupPopup(false)} + open={true}> +

+ In order for the SMS notifications to work, you'll first need to + configure Twilio. +

+ +
)} - {displayTransactionAlerts && ( -
- -
+ {emailSetupPopup && ( + setEmailSetupPopup(false)} + open={true}> +

+ In order for the mail notifications to work, you'll first need to + configure Mailgun. +

+ +
)} - {displayFiatAlerts && ( -
- - {displayOverrides && ( - - )} -
- )} - {displayCryptoAlerts && ( -
- - {displayOverrides && ( - - )} -
- )} -
+ ) ) } diff --git a/new-lamassu-admin/src/pages/Notifications/sections/Setup.js b/new-lamassu-admin/src/pages/Notifications/sections/Setup.js index 2cef2b38..2e8d7583 100644 --- a/new-lamassu-admin/src/pages/Notifications/sections/Setup.js +++ b/new-lamassu-admin/src/pages/Notifications/sections/Setup.js @@ -26,25 +26,33 @@ const sizes = { active: 263 } -const Row = ({ namespace, forceDisable, shouldUpperCase }) => { - const { data: rawData, save: rawSave } = useContext(NotificationsCtx) - - const save = R.compose(rawSave(null), toNamespace(namespace)) - const data = fromNamespace(namespace)(rawData) - +const Row = ({ + namespace, + data, + forceDisable, + save, + shouldUpperCase, + onActivation +}) => { const disabled = forceDisable || !data || !data.active const Cell = ({ name, disabled }) => { const value = !!(data && data[name]) + const onChange = event => { + if (name === 'active' && value === false) { + if (!onActivation()) return + } + + save({ [name]: event.target.checked }) + } + return ( { - save({ [name]: event.target.checked }) - }} + onChange={onChange} value={value} /> @@ -71,7 +79,46 @@ const useStyles = makeStyles({ width: 930 } }) + const Setup = ({ wizard, forceDisable }) => { + const { + data: rawData, + save: rawSave, + twilioAvailable, + setSmsSetupPopup, + mailgunAvailable, + setEmailSetupPopup + } = useContext(NotificationsCtx) + + const namespaces = [ + { + name: 'email', + forceDisable: forceDisable, + shouldUpperCase: false, + onActivation: () => { + if (mailgunAvailable) return true + setEmailSetupPopup(true) + return false + } + }, + { + name: 'sms', + forceDisable: forceDisable, + shouldUpperCase: true, + onActivation: () => { + if (twilioAvailable) return true + setSmsSetupPopup(true) + return false + } + }, + { + name: 'notificationCenter', + forceDisable: forceDisable, + shouldUpperCase: false, + onActivation: () => true + } + ] + const widthAdjust = wizard ? 20 : 0 const classes = useStyles() return ( @@ -85,9 +132,16 @@ const Setup = ({ wizard, forceDisable }) => { ))} - - - + {namespaces.map(namespace => ( + + ))} ) diff --git a/new-lamassu-admin/src/pages/Triggers/Triggers.js b/new-lamassu-admin/src/pages/Triggers/Triggers.js index 525134b5..7ba90185 100644 --- a/new-lamassu-admin/src/pages/Triggers/Triggers.js +++ b/new-lamassu-admin/src/pages/Triggers/Triggers.js @@ -5,11 +5,14 @@ import gql from 'graphql-tag' import * as R from 'ramda' import React, { useState } from 'react' +import Modal from 'src/components/Modal' import { HoverableTooltip } from 'src/components/Tooltip' -import { Link } from 'src/components/buttons' +import { Link, SupportLinkButton } from 'src/components/buttons' import { Switch } from 'src/components/inputs' import TitleSection from 'src/components/layout/TitleSection' import { P, Label2 } from 'src/components/typography' +import FormRenderer from 'src/pages/Services/FormRenderer' +import twilioSchema from 'src/pages/Services/schemas/twilio' import { ReactComponent as ReverseCustomInfoIcon } from 'src/styling/icons/circle buttons/filter/white.svg' import { ReactComponent as CustomInfoIcon } from 'src/styling/icons/circle buttons/filter/zodiac.svg' import { ReactComponent as ReverseSettingsIcon } from 'src/styling/icons/circle buttons/settings/white.svg' @@ -23,6 +26,12 @@ import AdvancedTriggers from './components/AdvancedTriggers' import { fromServer } from './helper' const useStyles = makeStyles(styles) +const SAVE_ACCOUNT = gql` + mutation Save($accounts: JSONObject) { + saveAccounts(accounts: $accounts) + } +` + const SAVE_CONFIG = gql` mutation Save($config: JSONObject) { saveConfig(config: $config) @@ -32,6 +41,7 @@ const SAVE_CONFIG = gql` const GET_CONFIG = gql` query getData { config + accounts } ` @@ -55,6 +65,8 @@ const Triggers = () => { const [error, setError] = useState(null) const [subMenu, setSubMenu] = useState(false) + const [twilioSetupPopup, setTwilioSetupPopup] = useState(false) + const customInfoRequests = R.path(['customInfoRequests'])(customInfoReqData) ?? [] const enabledCustomInfoRequests = R.filter(R.propEq('enabled', true))( @@ -72,6 +84,12 @@ const Triggers = () => { onError: error => setError(error) }) + const [saveAccount] = useMutation(SAVE_ACCOUNT, { + onCompleted: () => setTwilioSetupPopup(false), + refetchQueries: () => ['getData'], + onError: error => setError(error) + }) + const addressReuseSave = rawConfig => { const config = toNamespace('compliance')(rawConfig) return saveConfig({ variables: { config } }) @@ -98,6 +116,17 @@ const Triggers = () => { const loading = configLoading || customInfoLoading + const twilioSave = it => { + setError(null) + return saveAccount({ + variables: { accounts: { twilio: it } } + }) + } + const addNewTriger = () => { + if (!R.has('twilio', data?.accounts || {})) setTwilioSetupPopup(true) + else toggleWizard('newTrigger')() + } + return ( <> { )} {!loading && !subMenu && !R.isEmpty(triggers) && ( - toggleWizard('newTrigger')()}> + + Add new trigger @@ -191,6 +220,27 @@ const Triggers = () => { save={saveConfig} data={data}> )} + {twilioSetupPopup && ( + setTwilioSetupPopup(false)} + open={true}> +

+ In order for compliance triggers to work, you'll first need to + configure Twilio. +

+ + +
+ )} ) }