Skip to content
This repository has been archived by the owner on Aug 9, 2022. It is now read-only.

feat(notifier): adds notification channels #842

Merged
merged 8 commits into from
May 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/api/rif-marketplace-cache/notifier/offers/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { MinMaxFilter } from 'models/Filters'
import { SupportedFiatSymbol } from 'models/Fiat'
import { NotifierOffersFilters } from 'models/marketItems/NotifierFilters'
import { parseToBigDecimal } from 'utils/parsers'
import { SupportedEventChannel } from 'config/notifier'
import { NotifierAPIService } from '../interfaces'
import { PlanDTO } from './models'

Expand All @@ -31,7 +32,7 @@ export const mapFromTransport = ({
name,
provider: provider.toLocaleLowerCase(),
url,
channels: channels.map((channel) => channel.name),
channels: channels.map((channel) => channel.name as SupportedEventChannel),
limit: quantity,
priceOptions: prices.map((price) => ({
token: getSupportedTokenByName(
Expand Down
51 changes: 51 additions & 0 deletions src/components/organisms/RemovableRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { FC } from 'react'
import { makeStyles, Theme } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import { colors } from '@rsksmart/rif-ui'
import RemoveButton from 'components/atoms/RemoveButton'
import { SelectRowButtonProps } from 'components/molecules/SelectRowButton'

const useStyles = makeStyles((theme: Theme) => ({
innerContainer: {
backgroundColor: colors.transparent,
borderRadius: 10,
padding: theme.spacing(2),
border: `1px solid ${colors.gray3}`,
height: '25%',
},
removeButton: {
maxWidth: '20px',
maxHeight: '20px',
minWidth: '20px',
minHeight: '20px',
},
}))

const RemovableRow: FC<SelectRowButtonProps> = ({
className = '', children, id, handleSelect,
}) => {
const classes = useStyles()
return (
<Grid className={className} container alignItems="center" spacing={2}>
<Grid item xs={12}>
<Grid
container
alignItems="center"
className={classes.innerContainer}
spacing={1}
>
{children}
<Grid xs={3} item>
<RemoveButton
className={classes.removeButton}
id={id}
handleSelect={handleSelect}
/>
</Grid>
</Grid>
</Grid>
</Grid>
)
}

export default RemovableRow
32 changes: 32 additions & 0 deletions src/components/organisms/notifier/NotificationChannel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { FC } from 'react'
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 RemovableRow from 'components/organisms/RemovableRow'

export interface NotificationChannelProps {
className?: string
onRemoveClick: (e: any) => void
channel: NotifierChannel
}

const NotificationChannel: FC<NotificationChannelProps> = ({
channel, onRemoveClick,
}) => (
<RemovableRow id={channel.type} handleSelect={onRemoveClick}>
<Grid xs={3} item>
<Typography component="div">
<Box fontWeight="fontWeightMedium" textAlign="center" color={colors.gray5}>
{channel.type}
</Box>
</Typography>
</Grid>
<Grid xs={6} item style={{ display: 'flex', justifyContent: 'space-around', alignItems: 'center' }}>
{shortenString(channel.destination, 30, 25)}
</Grid>
</RemovableRow>
)

export default NotificationChannel
119 changes: 119 additions & 0 deletions src/components/organisms/notifier/NotificationChannelCreate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React, { FC, useState } from 'react'
import { makeStyles, Theme } from '@material-ui/core/styles'
import Grid from '@material-ui/core/Grid'
import { NotifierChannel } 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'
import { useForm } from 'react-hook-form'
import Typography from '@material-ui/core/Typography'
import validateURL from 'utils/validationUtils'
import { notifierChannelPlaceHolder } from 'constants/notifier/strings'
import { SUPPORTED_API_CHANNEL_PROTOCOLS, SupportedEventChannel } from 'config/notifier'

interface Props {
channelAdd: (notifierChannel: NotifierChannel) => void
availableChannels: Array<SupportedEventChannel>
}

const useStyles = makeStyles((theme: Theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
select: {
textAlign: 'center',
height: 40,
},
}))

type Inputs = {
destination: string
}

const NotificationChannelCreate: FC<Props> = ({
availableChannels, channelAdd,
}) => {
const [notifierChannel, setNotifierChannel] = useState<NotifierChannel>({
type: availableChannels[0],
destination: '',
})

const handleChannelChange = ({ target: { value } }) => {
setNotifierChannel({
...notifierChannel,
type: value,
})
}
const handleDestinationChange = ({ target: { value } }) => {
setNotifierChannel({
...notifierChannel,
destination: value,
})
}

const validateDestination = (destination: string) => {
if (notifierChannel.type === 'API') {
return validateURL(destination, SUPPORTED_API_CHANNEL_PROTOCOLS)
}
return true
}
const classes = useStyles()
const { register, handleSubmit, errors } = useForm<Inputs>()

return (
<Grid container spacing={4} alignItems="center">
<Grid item xs={2} md={2}>
<FormControl variant="outlined" className={classes.formControl}>
<Select
className={classes.select}
id="channel-select"
value={notifierChannel.type}
onChange={handleChannelChange}
>
{
availableChannels.map((channelType) => <MenuItem value={channelType}>{channelType}</MenuItem>)
}
</Select>
</FormControl>
</Grid>
<Grid item xs={7} md={7}>
<TextField
name="destination"
fullWidth
onChange={handleDestinationChange}
placeholder={notifierChannelPlaceHolder[notifierChannel.type]}
variant="outlined"
inputRef={register({ required: true, validate: validateDestination })}
InputProps={{
style: { height: 40 },
}}
/>
{
errors.destination && (
<Typography color="error" variant="caption">
Invalid destination
</Typography>
)
}
</Grid>
<Grid item xs={3} md={3}>
<SelectRowButton
id="add-channel"
handleSelect={
handleSubmit(() => channelAdd(notifierChannel))
}
size="large"
variant="outlined"
>
Add Channel
</SelectRowButton>
</Grid>
</Grid>

)
}

export default NotificationChannelCreate
95 changes: 95 additions & 0 deletions src/components/organisms/notifier/NotificationChannelsList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* 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 } from 'models/marketItems/NotifierItem'
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'
import { SupportedEventChannel, SUPPORTED_EVENT_CHANNELS } from 'config/notifier'

const useStyles = makeStyles((theme: Theme) => createStyles({

channelsList: {
marginTop: theme.spacing(2),
marginBottom: theme.spacing(4),
marginLeft: theme.spacing(15),
borderTop: `1px solid ${colors.gray3}`,
padding: theme.spacing(3, 0),
},

}))

type Props = {
channels?: Array<SupportedEventChannel>
}

const NotificationChannelsList: FC<Props> = ({ channels }) => {
const [addedChannels, setChannels] = useState<Array<NotifierChannel>>([])

const classes = useStyles()

if (!channels) {
return <Grid />
}
const availableChannels: Array<SupportedEventChannel> = channels.filter((channel) => SUPPORTED_EVENT_CHANNELS.includes(channel as SupportedEventChannel))

const addChannel = (notifierChannel: NotifierChannel) => {
const index = addedChannels.findIndex((channel) => channel.type === notifierChannel.type)

if (index === -1) addedChannels.push(notifierChannel)
else addedChannels[index].destination = notifierChannel.destination
const newChannels = [...addedChannels]
setChannels(newChannels)
}

const removeChannel = (event): void => {
const newChannels = addedChannels.filter((i) => i.type !== event.currentTarget.id)
setChannels(newChannels)
}

const collection = addedChannels.map((channel) => ({
type: channel.type,
destination: channel.destination,
}))

return (availableChannels.length ? (
<Grid>
<Typography gutterBottom variant="h6" color="primary">
Notification Channels
</Typography>
<Typography gutterBottom color="secondary" variant="body2">
Select the channel that you want to receive your notification through
</Typography>
<NotificationChannelCreate
availableChannels={availableChannels}
channelAdd={addChannel}
/>
<Grid className={classes.channelsList} item xs={12}>
<Grid alignItems="center" container spacing={2}>
{
collection.map((channel) => (
<NotificationChannel
channel={channel}
onRemoveClick={removeChannel}
/>
))
}
</Grid>
</Grid>
<GridRow justify="center" spacing={2}>
<RoundBtn type="submit">
Submit
</RoundBtn>
</GridRow>
</Grid>
) : <Grid />
)
}
export default NotificationChannelsList
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import React, {
} from 'react'

import {
Grid,
Grid, makeStyles,
Typography,
} from '@material-ui/core'
import { NotifierOffersContextProps as ContextProps, NotifierOffersContext } from 'context/Services/notifier/offers'
Expand All @@ -16,6 +16,15 @@ 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'
import { createStyles, Theme } from '@material-ui/core/styles'

const useStyles = makeStyles((theme: Theme) => createStyles({

eventsSection: {
marginTop: theme.spacing(4),
},
}))

const eventHeaders = {
name: 'Name',
Expand All @@ -31,6 +40,7 @@ type EventItem = Item & {
}

const NotifierOffersSelectedPage: FC = () => {
const classes = useStyles()
const {
state: {
exchangeRates: {
Expand Down Expand Up @@ -90,9 +100,7 @@ const NotifierOffersSelectedPage: FC = () => {
</Grid>
<NotifierPlanDescription {...{ item: order, crypto, currentFiat }} />
{/* Header */ }
<Grid item xs={11} md="auto">
<br />
<br />
<Grid item xs={11} md="auto" className={classes.eventsSection}>
<Typography gutterBottom variant="h6" color="primary">
Notification events added
</Typography>
Expand All @@ -109,6 +117,9 @@ const NotifierOffersSelectedPage: FC = () => {
<Button variant="outlined" color="primary" rounded>
+ Add Notification Events
</Button>
<br />
<br />
Comment on lines +120 to +121
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use grid to position things on page instead.

<NotificationChannelsList {...{ channels: order?.item.channels }} />
</CenteredPageTemplate>
)
}
Expand Down
4 changes: 4 additions & 0 deletions src/config/notifier/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type SupportedEventChannel = | 'API'

export const SUPPORTED_EVENT_CHANNELS: Array<SupportedEventChannel> = ['API']
export const SUPPORTED_API_CHANNEL_PROTOCOLS = ['http:', 'https:']
7 changes: 7 additions & 0 deletions src/constants/notifier/strings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { SupportedEventChannel } from 'config/notifier'

export const notifierChannelPlaceHolder: Record<SupportedEventChannel, string> = {
API: 'Enter api destination',
}

export default {}
Loading