2022-01-02 20:42:59 -08:00
|
|
|
import React, { FunctionComponent, useEffect, useState } from 'react'
|
|
|
|
import { PlusCircleIcon, TrashIcon } from '@heroicons/react/outline'
|
|
|
|
import Modal from './Modal'
|
2022-02-22 15:30:54 -08:00
|
|
|
import Input, { Label } from './Input'
|
2022-01-02 20:42:59 -08:00
|
|
|
import { ElementTitle } from './styles'
|
|
|
|
import useMangoStore from '../stores/useMangoStore'
|
|
|
|
import Button, { LinkButton } from './Button'
|
|
|
|
import { notify } from '../utils/notifications'
|
|
|
|
import { useTranslation } from 'next-i18next'
|
|
|
|
import ButtonGroup from './ButtonGroup'
|
|
|
|
import InlineNotification from './InlineNotification'
|
|
|
|
|
|
|
|
interface CreateAlertModalProps {
|
|
|
|
onClose: () => void
|
|
|
|
isOpen: boolean
|
|
|
|
repayAmount?: string
|
|
|
|
tokenSymbol?: string
|
|
|
|
}
|
|
|
|
|
|
|
|
const CreateAlertModal: FunctionComponent<CreateAlertModalProps> = ({
|
|
|
|
isOpen,
|
|
|
|
onClose,
|
|
|
|
}) => {
|
2022-01-18 11:41:14 -08:00
|
|
|
const { t } = useTranslation(['common', 'alerts'])
|
2022-01-02 20:42:59 -08:00
|
|
|
const actions = useMangoStore((s) => s.actions)
|
|
|
|
const mangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
|
|
|
const mangoAccount = useMangoStore((s) => s.selectedMangoAccount.current)
|
|
|
|
const activeAlerts = useMangoStore((s) => s.alerts.activeAlerts)
|
|
|
|
const loading = useMangoStore((s) => s.alerts.loading)
|
|
|
|
const submitting = useMangoStore((s) => s.alerts.submitting)
|
|
|
|
const error = useMangoStore((s) => s.alerts.error)
|
|
|
|
const [email, setEmail] = useState<string>('')
|
|
|
|
const [invalidAmountMessage, setInvalidAmountMessage] = useState('')
|
|
|
|
const [health, setHealth] = useState('')
|
|
|
|
const [showCustomHealthForm, setShowCustomHealthForm] = useState(false)
|
|
|
|
const [showAlertForm, setShowAlertForm] = useState(false)
|
|
|
|
|
|
|
|
const healthPresets = ['5', '10', '15', '25', '30']
|
|
|
|
|
|
|
|
const validateEmailInput = (amount) => {
|
|
|
|
if (Number(amount) <= 0) {
|
|
|
|
setInvalidAmountMessage(t('enter-amount'))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const onChangeEmailInput = (amount) => {
|
|
|
|
setEmail(amount)
|
|
|
|
setInvalidAmountMessage('')
|
|
|
|
}
|
|
|
|
|
|
|
|
async function onCreateAlert() {
|
|
|
|
if (!email) {
|
|
|
|
notify({
|
2022-01-18 11:41:14 -08:00
|
|
|
title: t('alerts:email-address-required'),
|
2022-01-02 20:42:59 -08:00
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
return
|
|
|
|
} else if (!health) {
|
|
|
|
notify({
|
2022-01-18 11:41:14 -08:00
|
|
|
title: t('alerts:alert-health-required'),
|
2022-01-02 20:42:59 -08:00
|
|
|
type: 'error',
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const body = {
|
|
|
|
mangoGroupPk: mangoGroup.publicKey.toString(),
|
|
|
|
mangoAccountPk: mangoAccount.publicKey.toString(),
|
|
|
|
health,
|
|
|
|
alertProvider: 'mail',
|
|
|
|
email,
|
|
|
|
}
|
|
|
|
const success: any = await actions.createAlert(body)
|
|
|
|
if (success) {
|
|
|
|
setShowAlertForm(false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleCancelCreateAlert = () => {
|
|
|
|
if (activeAlerts.length > 0) {
|
|
|
|
setShowAlertForm(false)
|
|
|
|
} else {
|
|
|
|
onClose()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
actions.loadAlerts(mangoAccount.publicKey)
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
return (
|
|
|
|
<Modal isOpen={isOpen} onClose={onClose}>
|
|
|
|
{!loading && !submitting ? (
|
|
|
|
<>
|
|
|
|
{activeAlerts.length > 0 && !showAlertForm ? (
|
|
|
|
<>
|
|
|
|
<Modal.Header>
|
2022-03-09 12:53:11 -08:00
|
|
|
<div className="flex w-full items-center justify-between">
|
2022-01-02 20:42:59 -08:00
|
|
|
<div className="w-20" />
|
2022-02-19 13:58:21 -08:00
|
|
|
<ElementTitle noMarginBottom>
|
2022-01-18 11:41:14 -08:00
|
|
|
{t('alerts:active-alerts')}
|
2022-01-02 20:42:59 -08:00
|
|
|
</ElementTitle>
|
|
|
|
<Button
|
2022-03-09 12:53:11 -08:00
|
|
|
className="min-w-20 flex h-8 items-center justify-center pt-0 pb-0 text-xs"
|
2022-02-20 19:55:13 -08:00
|
|
|
disabled={activeAlerts.length >= 5}
|
2022-01-02 20:42:59 -08:00
|
|
|
onClick={() => setShowAlertForm(true)}
|
|
|
|
>
|
|
|
|
<div className="flex items-center">
|
2022-03-09 12:53:11 -08:00
|
|
|
<PlusCircleIcon className="mr-1.5 h-4 w-4" />
|
2022-02-26 09:38:31 -08:00
|
|
|
{t('alerts:new-alert')}
|
2022-01-02 20:42:59 -08:00
|
|
|
</div>
|
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
</Modal.Header>
|
2022-03-09 12:53:11 -08:00
|
|
|
<div className="mt-2 border-b border-th-fgd-4">
|
2022-01-02 20:42:59 -08:00
|
|
|
{activeAlerts.map((alert, index) => (
|
|
|
|
<div
|
2022-03-09 12:53:11 -08:00
|
|
|
className="flex items-center justify-between border-t border-th-fgd-4 p-4"
|
2022-01-02 20:42:59 -08:00
|
|
|
key={`${alert._id}${index}`}
|
|
|
|
>
|
|
|
|
<div className="text-th-fgd-1">
|
2022-01-18 11:41:14 -08:00
|
|
|
{t('alerts:alert-info', { health: alert.health })}
|
2022-01-02 20:42:59 -08:00
|
|
|
</div>
|
|
|
|
<TrashIcon
|
2022-03-09 12:53:11 -08:00
|
|
|
className="default-transition h-5 w-5 cursor-pointer text-th-fgd-3 hover:text-th-primary"
|
2022-01-02 20:42:59 -08:00
|
|
|
onClick={() => actions.deleteAlert(alert._id)}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
))}
|
|
|
|
</div>
|
|
|
|
{activeAlerts.length >= 3 ? (
|
|
|
|
<div className="mt-1 text-center text-xxs text-th-fgd-3">
|
2022-01-18 11:41:14 -08:00
|
|
|
{t('alerts:alerts-max')}
|
2022-01-02 20:42:59 -08:00
|
|
|
</div>
|
|
|
|
) : null}
|
|
|
|
</>
|
|
|
|
) : showAlertForm ? (
|
|
|
|
<>
|
2022-02-20 19:55:13 -08:00
|
|
|
<Modal.Header>
|
2022-02-22 15:03:27 -08:00
|
|
|
<ElementTitle noMarginBottom>
|
|
|
|
{t('alerts:create-alert')}
|
|
|
|
</ElementTitle>
|
|
|
|
<p className="mt-1 text-center">
|
|
|
|
{t('alerts:alerts-disclaimer')}
|
|
|
|
</p>
|
2022-02-20 19:55:13 -08:00
|
|
|
</Modal.Header>
|
2022-01-02 20:42:59 -08:00
|
|
|
{error ? (
|
|
|
|
<div className="my-4">
|
|
|
|
<InlineNotification title={error} type="error" />
|
|
|
|
</div>
|
|
|
|
) : null}
|
2022-02-22 15:30:54 -08:00
|
|
|
<Label>{t('email-address')}</Label>
|
2022-01-02 20:42:59 -08:00
|
|
|
<Input
|
|
|
|
type="email"
|
|
|
|
error={!!invalidAmountMessage}
|
|
|
|
onBlur={(e) => validateEmailInput(e.target.value)}
|
|
|
|
value={email || ''}
|
|
|
|
onChange={(e) => onChangeEmailInput(e.target.value)}
|
|
|
|
/>
|
2022-03-09 12:53:11 -08:00
|
|
|
<div className="mt-4 flex items-end">
|
2022-01-02 20:42:59 -08:00
|
|
|
<div className="w-full">
|
2022-02-22 15:30:54 -08:00
|
|
|
<div className="flex justify-between">
|
2022-02-22 16:51:35 -08:00
|
|
|
<Label>{t('alerts:alert-health')}</Label>
|
|
|
|
|
2022-01-02 20:42:59 -08:00
|
|
|
<LinkButton
|
2022-02-22 15:30:54 -08:00
|
|
|
className="mb-1.5"
|
2022-01-02 20:42:59 -08:00
|
|
|
onClick={() =>
|
|
|
|
setShowCustomHealthForm(!showCustomHealthForm)
|
|
|
|
}
|
|
|
|
>
|
|
|
|
{showCustomHealthForm ? t('presets') : t('custom')}
|
|
|
|
</LinkButton>
|
|
|
|
</div>
|
|
|
|
{showCustomHealthForm ? (
|
|
|
|
<Input
|
|
|
|
type="number"
|
|
|
|
min="0"
|
|
|
|
max="100"
|
|
|
|
onChange={(e) => setHealth(e.target.value)}
|
|
|
|
suffix={
|
2022-03-09 12:53:11 -08:00
|
|
|
<div className="text-base font-bold text-th-fgd-3">
|
2022-01-02 20:42:59 -08:00
|
|
|
%
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
value={health}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<ButtonGroup
|
|
|
|
activeValue={health.toString()}
|
|
|
|
onChange={(p) => setHealth(p)}
|
|
|
|
unit="%"
|
|
|
|
values={healthPresets}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
</div>
|
2022-02-20 19:55:13 -08:00
|
|
|
<Button className="mt-6 w-full" onClick={() => onCreateAlert()}>
|
2022-02-22 10:54:44 -08:00
|
|
|
{t('alerts:create-alert')}
|
2022-02-20 19:55:13 -08:00
|
|
|
</Button>
|
|
|
|
<LinkButton
|
2022-03-09 12:53:11 -08:00
|
|
|
className="mt-4 w-full text-center"
|
2022-02-20 19:55:13 -08:00
|
|
|
onClick={handleCancelCreateAlert}
|
|
|
|
>
|
|
|
|
{t('cancel')}
|
|
|
|
</LinkButton>
|
2022-01-02 20:42:59 -08:00
|
|
|
</>
|
|
|
|
) : error ? (
|
|
|
|
<div>
|
|
|
|
<InlineNotification title={error} type="error" />
|
|
|
|
<Button
|
2022-03-09 12:53:11 -08:00
|
|
|
className="mx-auto mt-6 flex justify-center"
|
2022-01-02 20:42:59 -08:00
|
|
|
onClick={() => actions.loadAlerts()}
|
|
|
|
>
|
|
|
|
{t('try-again')}
|
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
) : (
|
|
|
|
<div>
|
|
|
|
<Modal.Header>
|
2022-02-22 15:03:27 -08:00
|
|
|
<ElementTitle noMarginBottom>
|
|
|
|
{t('alerts:no-alerts')}
|
|
|
|
</ElementTitle>
|
2022-02-22 10:54:44 -08:00
|
|
|
<p className="mt-1 text-center">{t('alerts:no-alerts-desc')}</p>
|
2022-01-02 20:42:59 -08:00
|
|
|
</Modal.Header>
|
|
|
|
<Button
|
2022-03-09 12:53:11 -08:00
|
|
|
className="m-auto flex justify-center"
|
2022-01-02 20:42:59 -08:00
|
|
|
onClick={() => setShowAlertForm(true)}
|
|
|
|
>
|
2022-01-18 11:41:14 -08:00
|
|
|
{t('alerts:new-alert')}
|
2022-01-02 20:42:59 -08:00
|
|
|
</Button>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</>
|
|
|
|
) : (
|
|
|
|
<div className="space-y-3">
|
2022-03-09 12:53:11 -08:00
|
|
|
<div className="h-12 w-full animate-pulse rounded-md bg-th-bkg-3" />
|
|
|
|
<div className="h-12 w-full animate-pulse rounded-md bg-th-bkg-3" />
|
|
|
|
<div className="h-12 w-full animate-pulse rounded-md bg-th-bkg-3" />
|
2022-01-02 20:42:59 -08:00
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</Modal>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
export default React.memo(CreateAlertModal)
|