-
Notifications
You must be signed in to change notification settings - Fork 6
feat(notifier): adds notification channels #842
Conversation
ea40d49
to
551c7e7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks good. Just please consider those 2 comment:
- Template the component we wanted to reuse instead of copying it
- Use
react-hook-form
library for data input
<Grid xs={6} item style={{ display: 'flex', justifyContent: 'space-around', alignItems: 'center' }}> | ||
{shortenString(channel.destination, 30, 25)} | ||
</Grid> | ||
<Grid xs={3} item> | ||
<RemoveButton | ||
style={{ | ||
maxWidth: '20px', maxHeight: '20px', minWidth: '20px', minHeight: '20px', | ||
}} | ||
id={channel.type} | ||
handleSelect={onRemoveClick} | ||
/> | ||
</Grid> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, prefer classes instead of inline styles. See this SO question for more info
<Grid | ||
container | ||
alignItems="center" | ||
className={classes.innerContainer} | ||
spacing={1} | ||
> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this is the same row styles we were talking about, I think it would be best to template it. That way we could reuse it here and if we want to change it in the future we would only need to do the change in one place.
destination: channel.destination, | ||
})) | ||
|
||
return ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know we have a lot of Grid
components acting as forms, but we are trying to migrate them to https://react-hook-form.com/. With that we don't need to create validations for emails for example. It also improves UX.
See #710 and #709 for reference
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple more changes from me too, please.
export enum NotifierChannelType { | ||
API = 'Enter api destination', | ||
EMAIL = 'Enter your email' | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer using const assertion to enums, unless you'd benefit from bidirectional resolution. See https://tinyurl.com/enumconst
src/utils/validationUtils.ts
Outdated
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 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's not validate emails in the UI.
- expensive
- doesn't actually validate the email address
once we do start using email in channels, we should send a verification email instead.
<br /> | ||
<br /> |
There was a problem hiding this comment.
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.
<br /> | ||
<br /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't need this. use grid and/or css
if (!validate(notifierChannel)) { | ||
return | ||
} | ||
const index = addedChannels.findIndex((ch) => ch.type === notifierChannel.type) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use meaningful variable names (yea, even for iterator arguments)
if (!validate(notifierChannel)) { | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use the forms dependency for validation, if needed. (would not worry about that right now tbh tho)
if (!channels) { | ||
return <Grid /> | ||
} | ||
const availableChannels: Array<string> = channels.map((ch) => (NotifierChannelType[ch] ? ch : '')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please use meaningful variable names (yea, even for iterator arguments)
const [destination, setDestination] = useState<string>('') | ||
const handleChange = (e) => { | ||
setChannel({ | ||
type: e.target.value as string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
destructure {target} or {target: {value}}
2fb2a8f
to
2bbd003
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple more bits & bobs.
src/utils/validationUtils.ts
Outdated
const validateURL = (_url: string): boolean => { | ||
let url | ||
try { | ||
url = new URL(_url) | ||
} catch (_) { | ||
return false | ||
} | ||
return url.protocol === 'http:' || url.protocol === 'https:' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to use a constant for the valid protocols. Also, we're trying to keep the use of mutable variables close to none. Another point is to try not to use arg names with underscore prefix. In fact I'm surprised eslint didn't complain about that. I suggest following structure:
const validateURL = (_url: string): boolean => { | |
let url | |
try { | |
url = new URL(_url) | |
} catch (_) { | |
return false | |
} | |
return url.protocol === 'http:' || url.protocol === 'https:' | |
const EVENT_API_AVAILABLE_PROTOCOLS = [ 'http:', 'https:'] // we could potentially make this configurable, for sure we should move it somewhere more in scope of the notifier service | |
const validateURLProtocol = (url: string, validProtocols: Array<string>): boolean => { | |
try { | |
const { protocol } = new URL(url) | |
return validProtocols.includes(protocol); | |
} catch { // note that catch in js doesn't need arguments | |
return false | |
} | |
} |
if (!channels) { | ||
return <Grid /> | ||
} | ||
const availableChannels: Array<string> = channels.map((channel) => (notifierChannelType[channel] ? channel : '')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get that you want to restrict the use to only those currently supported channels with this. If so, then we should make this either configurable, or a constant somewhere. However, one that represents this, like const EVENT_AVAILABLE_CHANNELS = ['API']
(currently just that API I think. Is that right @artem-brazhnikov?).
Another thing here is that maybe use .filter
instead of mapping to potentially empty string.
import Typography from '@material-ui/core/Typography' | ||
import validateURL from 'utils/validationUtils' | ||
|
||
export interface NotificationChannelCreateProps { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As not used outside just call it Props
@@ -29,3 +29,13 @@ export type NotifierSubscriptionItem = Item & Omit<SubscriptionDTO, 'hash' | 'pr | |||
price: Big | |||
token: SupportedToken | |||
} | |||
|
|||
export const notifierChannelType = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry didn't pick up on this before, but let's call this notifierChannelPlaceholder
and move it to the src/components/organisms/notifier/NotificationChannelCreate.tsx
as it is not needed for any other areas of the UI.
9d5d06e
to
7a7c686
Compare
} | ||
</Grid> | ||
<Grid item xs={3} md={3}> | ||
<SelectRowButton id="add-channel" handleSelect={handleSubmit(() => channelAdd(notifierChannel))} size="large" variant="outlined">Add Channel</SelectRowButton> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
split to multiple lines
})) | ||
|
||
type Props = { | ||
channels: string[] | undefined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
channels?: Array< SupportedEventChannel>
if (!channels) { | ||
return <Grid /> | ||
} | ||
const availableChannels: Array<string> = channels.filter((channel) => SUPPORTED_EVENT_CHANNELS.indexOf(channel as SupportedEventChannel) !== -1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- multiple lines
const availableChannels: Array< SupportedEventChannel>
- SUPPORTED_EVENT_CHANNELS.includes(channel)
src/utils/validationUtils.ts
Outdated
@@ -0,0 +1,10 @@ | |||
export const EVENT_API_AVAILABLE_PROTOCOLS = ['http:', 'https:'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be in the notifier config now. (also could you please rename it to match the other const please? my bad, sorry)
Adds Notification channels section in notifier buy checkout page