From 551c7e77373221c5fbb8d9fabb02dac7bfd5437d Mon Sep 17 00:00:00 2001 From: Vijay Krishna <11134695+vjgene@users.noreply.github.com> Date: Mon, 10 May 2021 23:49:53 +0530 Subject: [PATCH] feat(notifier): add notification channels --- .../notifier/NotificationChannel.tsx | 71 ++++++++++ .../notifier/NotificationChannelCreate.tsx | 70 ++++++++++ .../notifier/NotificationChannelsList.tsx | 124 ++++++++++++++++++ .../buy/NotifierOffersSelectedPage.tsx | 4 + src/models/marketItems/NotifierItem.ts | 10 ++ src/utils/validationUtils.ts | 18 +++ 6 files changed, 297 insertions(+) create mode 100644 src/components/organisms/notifier/NotificationChannel.tsx create mode 100644 src/components/organisms/notifier/NotificationChannelCreate.tsx create mode 100644 src/components/organisms/notifier/NotificationChannelsList.tsx create mode 100644 src/utils/validationUtils.ts diff --git a/src/components/organisms/notifier/NotificationChannel.tsx b/src/components/organisms/notifier/NotificationChannel.tsx new file mode 100644 index 000000000..2fb588e4d --- /dev/null +++ b/src/components/organisms/notifier/NotificationChannel.tsx @@ -0,0 +1,71 @@ +import React, { FC } from 'react' +import { makeStyles, Theme } from '@material-ui/core/styles' +import Grid from '@material-ui/core/Grid' +import Typography from '@material-ui/core/Typography' +import Box from '@material-ui/core/Box' +import { colors, shortenString } from '@rsksmart/rif-ui' +import { NotifierChannel } from 'models/marketItems/NotifierItem' +import RemoveButton from 'components/atoms/RemoveButton' + +export interface NotificationChannelProps { + className?: string + onRemoveClick: (e: any) => void + channel: NotifierChannel +} + +const useStyles = makeStyles((theme: Theme) => ({ + innerContainer: { + backgroundColor: colors.transparent, + borderRadius: 10, + padding: theme.spacing(2), + border: `1px solid ${colors.gray3}`, + height: '25%', + }, + leftContent: { + [theme.breakpoints.up('sm')]: { + borderRight: `1px solid ${colors.gray3}`, + }, + }, +})) + +const NotificationChannel: FC = ({ + className = '', channel, onRemoveClick, +}) => { + const classes = useStyles() + + return ( + + + + + + + {channel.type} + + + + + {shortenString(channel.destination, 30, 25)} + + + + + + + + + ) +} + +export default NotificationChannel diff --git a/src/components/organisms/notifier/NotificationChannelCreate.tsx b/src/components/organisms/notifier/NotificationChannelCreate.tsx new file mode 100644 index 000000000..56b2b7206 --- /dev/null +++ b/src/components/organisms/notifier/NotificationChannelCreate.tsx @@ -0,0 +1,70 @@ +import React, { FC } from 'react' +import { makeStyles, Theme } from '@material-ui/core/styles' +import Grid from '@material-ui/core/Grid' +import { NotifierChannel, NotifierChannelType } from 'models/marketItems/NotifierItem' +import { FormControl } from '@material-ui/core' +import Select from '@material-ui/core/Select' +import MenuItem from '@material-ui/core/MenuItem' +import TextField from '@material-ui/core/TextField' +import { SelectRowButton } from 'components/molecules' + +export interface NotificationChannelCreateProps { + onChannelChange: (e: any) => void + onDestinationChange: (e: any) => void + notifierChannel: NotifierChannel + channelAdd: () => void + availableChannels: string[] +} + +const useStyles = makeStyles((theme: Theme) => ({ + formControl: { + margin: theme.spacing(1), + minWidth: 120, + }, + select: { + textAlign: 'center', + height: 40, + }, +})) + +const NotificationChannelCreate: FC = ({ + notifierChannel, availableChannels, onChannelChange, onDestinationChange, channelAdd, +}) => { + const classes = useStyles() + + return ( + + + + + + + + + + + Add Channel + + + + ) +} + +export default NotificationChannelCreate diff --git a/src/components/organisms/notifier/NotificationChannelsList.tsx b/src/components/organisms/notifier/NotificationChannelsList.tsx new file mode 100644 index 000000000..9eb08986f --- /dev/null +++ b/src/components/organisms/notifier/NotificationChannelsList.tsx @@ -0,0 +1,124 @@ +/* eslint-disable @typescript-eslint/no-empty-function */ +import { + Grid, makeStyles, Typography, +} from '@material-ui/core' +import React, { + FC, useState, +} from 'react' +import { createStyles, Theme } from '@material-ui/core/styles' +import { NotifierChannel, NotifierChannelType } from 'models/marketItems/NotifierItem' +import { validateEmail, validateURL } from 'utils/validationUtils' +import RoundBtn from 'components/atoms/RoundBtn' +import GridRow from 'components/atoms/GridRow' +import NotificationChannel from 'components/organisms/notifier/NotificationChannel' +import { colors } from '@rsksmart/rif-ui' +import NotificationChannelCreate from 'components/organisms/notifier/NotificationChannelCreate' + +const useStyles = makeStyles((theme: Theme) => createStyles({ + + channelsList: { + marginTop: theme.spacing(2), + marginLeft: theme.spacing(15), + borderTop: `1px solid ${colors.gray3}`, + padding: theme.spacing(3, 0), + }, + notificationChannel: { + }, + +})) + +type Props = + { + channels: string[] | undefined +} + +const NotificationChannelsList: FC = ({ channels }) => { + const [notifierChannel, setChannel] = useState({ + type: channels ? channels[0] : '', + destination: '', + }) + const [addedChannels, setChannels] = useState>([]) + const [destination, setDestination] = useState('') + const handleChange = (e) => { + setChannel({ + type: e.target.value as string, + destination: '', + }) + } + const classes = useStyles() + + if (!channels) { + return + } + const availableChannels: Array = channels.map((ch) => (NotifierChannelType[ch] ? ch : '')) + + const validate = (channel: NotifierChannel) => { + if (channel.destination) { + if (channel.type === 'API') { + return validateURL(channel.destination) + } + + if (channel.type === 'EMAIL') { + return validateEmail(channel.destination) + } + } + return false + } + + const addChannel = () => { + notifierChannel.destination = destination + + if (!validate(notifierChannel)) { + return + } + const index = addedChannels.findIndex((ch) => ch.type === notifierChannel.type) + + if (index === -1) addedChannels.push(notifierChannel) + else addedChannels[index].destination = destination + const newChannels = [...addedChannels] + setChannels(newChannels) + } + + const removeChannel = (e): void => { + const newChannels = addedChannels.filter((i) => i.type !== e.currentTarget.id) + setChannels(newChannels) + } + + const collection = addedChannels.map((channel) => ({ + type: channel.type, + destination: channel.destination, + })) + + return ( + + + Notification Channels + + + Select the channel that you want to receive your notification through + + setDestination(e.currentTarget.value)} + onChannelChange={handleChange} + channelAdd={addChannel} + /> + + + { + collection.map((channel) => ) + } + + +
+
+ + + Submit + + +
+ ) +} +export default NotificationChannelsList diff --git a/src/components/pages/notifier/buy/NotifierOffersSelectedPage.tsx b/src/components/pages/notifier/buy/NotifierOffersSelectedPage.tsx index 2558c514a..24f50b3af 100644 --- a/src/components/pages/notifier/buy/NotifierOffersSelectedPage.tsx +++ b/src/components/pages/notifier/buy/NotifierOffersSelectedPage.tsx @@ -16,6 +16,7 @@ import TableContainer from '@material-ui/core/TableContainer' import { Item } from 'models/Market' import RemoveButton from 'components/atoms/RemoveButton' import Tooltip from '@material-ui/core/Tooltip' +import NotificationChannelsList from 'components/organisms/notifier/NotificationChannelsList' const eventHeaders = { name: 'Name', @@ -109,6 +110,9 @@ const NotifierOffersSelectedPage: FC = () => { +
+
+ ) } diff --git a/src/models/marketItems/NotifierItem.ts b/src/models/marketItems/NotifierItem.ts index 2df1d02a6..b05e90038 100644 --- a/src/models/marketItems/NotifierItem.ts +++ b/src/models/marketItems/NotifierItem.ts @@ -29,3 +29,13 @@ export type NotifierSubscriptionItem = Item & Omit { + let url + try { + url = new URL(_url) + } catch (_) { + return false + } + return url.protocol === 'http:' || url.protocol === 'https:' +} + +export const validateEmail = (emails: string): boolean => { + const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ + let valid = true + emails.split(';').forEach((email) => { + if (re.test(String(email).toLowerCase()) === false) valid = false + }) + return valid +}