Skip to content

Commit

Permalink
Add notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
lvn-alduin committed Sep 9, 2024
1 parent b396e76 commit d4b52d7
Show file tree
Hide file tree
Showing 18 changed files with 437 additions and 28 deletions.
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"bignumber.js": "^9.1.2",
"graz": "^0.1.19",
"jdenticon": "^3.3.0",
"notistack": "^3.0.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.0.13",
Expand Down
34 changes: 34 additions & 0 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 11 additions & 2 deletions frontend/src/api/mutations/PlaceBet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { SigningCosmWasmClient } from '@cosmjs/cosmwasm-stargate'

import { useCurrentAccount } from '@config/chain'
import { NTRN_DENOM } from '@config/environment'
import { useNotifications } from '@config/notifications'
import { querierAwaitCacheAnd, querierBroadcastAndWait } from '@api/querier'
import { MarketId, OutcomeId } from '@api/queries/Market'
import { POSITIONS_KEYS } from '@api/queries/Positions'
import { NTRN } from '@utils/tokens'
import { errorsMiddleware } from '@utils/errors'
import { AppError, errorsMiddleware } from '@utils/errors'

interface PlaceBetRequest {
deposit: {
Expand Down Expand Up @@ -50,6 +51,7 @@ const usePlaceBet = (marketId: MarketId) => {
const account = useCurrentAccount()
const signer = useCosmWasmSigningClient()
const queryClient = useQueryClient()
const notifications = useNotifications()

const mutation = useMutation({
mutationKey: PLACE_BET_KEYS.market(account.bech32Address, marketId),
Expand All @@ -60,11 +62,18 @@ const usePlaceBet = (marketId: MarketId) => {
return Promise.reject()
}
},
onSuccess: () => {
onSuccess: (_, args) => {
notifications.notifySuccess(`Successfully bet ${args.ntrnAmount.toFormat(true)}.`)

return querierAwaitCacheAnd(
() => queryClient.invalidateQueries({ queryKey: POSITIONS_KEYS.market(account.bech32Address, marketId)}),
)
},
onError: (err, args) => {
notifications.notifyError(
AppError.withCause(`Failed to bet ${args.ntrnAmount.toFormat(true)}.`, err)
)
},
})

return mutation
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Stack } from "@mui/joy"
import { Outlet, ScrollRestoration } from "react-router-dom"
import { Stack } from '@mui/joy'
import { Outlet, ScrollRestoration } from 'react-router-dom'

import { Navbar } from "@common/Navbar"
import { Footer } from "@common/Footer"
import { Navbar } from '@common/Navbar'
import { Footer } from '@common/Footer'

const App = () => {
return (
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/assets/icons/ErrorNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { SvgIcon, SvgIconProps } from '@mui/joy'

const ErrorNotificationIcon = (props: SvgIconProps) => {
const Svg = () => (
<g>
<circle cx="27" cy="27" r="27" fill="#E52574"/>
<circle opacity="0.5" cx="27" cy="27" r="19.5" stroke="white" strokeWidth="3"/>
<rect x="19" y="20.0728" width="4" height="6" rx="2" fill="#D9D9D9"/>
<rect x="31" y="20.0728" width="4" height="6" rx="2" fill="#D9D9D9"/>
<path d="M21 34.5728V34.5728C24.4495 33.5777 28.0219 33.0728 31.612 33.0728H33" stroke="#D9D9D9" strokeWidth="3" strokeLinecap="round"/>
</g>
)

return (
<SvgIcon {...props} viewBox="0 0 54 54">
<Svg />
</SvgIcon>
)
}

export { ErrorNotificationIcon }
19 changes: 19 additions & 0 deletions frontend/src/assets/icons/SuccessNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { SvgIcon, SvgIconProps } from '@mui/joy'

const SuccessNotificationIcon = (props: SvgIconProps) => {
const Svg = () => (
<g>
<circle cx="27" cy="27" r="27" fill="#44C194"/>
<circle opacity="0.5" cx="26.9997" cy="27" r="19.9773" stroke="white" strokeWidth="3"/>
<path d="M21.4775 28.1206L22.6685 29.3892C23.638 30.422 25.2781 30.422 26.2476 29.3892L32.523 22.7046" stroke="white" strokeWidth="3" strokeLinecap="round"/>
</g>
)

return (
<SvgIcon {...props} viewBox="0 0 54 54">
<Svg />
</SvgIcon>
)
}

export { SuccessNotificationIcon }
15 changes: 15 additions & 0 deletions frontend/src/assets/icons/Tick.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { SvgIcon, SvgIconProps } from '@mui/joy'

const TickIcon = (props: SvgIconProps) => {
const Svg = () => (
<path d="M8.79496 15.875L4.62496 11.705L3.20496 13.115L8.79496 18.705L20.795 6.705L19.385 5.295L8.79496 15.875Z" />
)

return (
<SvgIcon {...props} viewBox="0 0 24 24">
<Svg />
</SvgIcon>
)
}

export { TickIcon }
18 changes: 18 additions & 0 deletions frontend/src/assets/icons/WarningNotification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { SvgIcon, SvgIconProps } from '@mui/joy'

const WarningNotificationIcon = (props: SvgIconProps) => {
const Svg = () => (
<g>
<circle cx="27" cy="27" r="27" fill="#FFB82E"/>
<circle opacity="0.5" cx="27" cy="27" r="19.5" stroke="white" strokeWidth="3"/>
</g>
)

return (
<SvgIcon {...props} viewBox="0 0 54 54">
<Svg />
</SvgIcon>
)
}

export { WarningNotificationIcon }
5 changes: 4 additions & 1 deletion frontend/src/components/common/ConnectionModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { WalletType, checkWallet, useConnect } from 'graz'
import { Button, DialogContent, DialogTitle, ModalClose, ModalDialog, Sheet } from '@mui/joy'

import { CHAIN_INFO } from '@config/chain'
import { useNotifications } from '@config/notifications'
import { dismiss, present } from '@state/modals'
import { AppError } from '@utils/errors'

const CONNECTION_MODAL_KEY = "connection_modal"

Expand Down Expand Up @@ -41,6 +43,7 @@ const supportedWallets: WalletOption[] = [

const ConnectionModal = () => {
const { connectAsync } = useConnect()
const notifications = useNotifications()

return (
<ModalDialog>
Expand All @@ -64,7 +67,7 @@ const ConnectionModal = () => {
.then(() => { dismissConnectionModal() })
.catch(err => {
if (!(err instanceof Error && err.message === "Request rejected") && !(err instanceof Error && err.message === "User closed wallet connect")) {
// notifications.notifyError(AppError.withCause(`Failed to connect with ${wallet.name}`, err))
notifications.notifyError(AppError.withCause(`Failed to connect with ${wallet.name}`, err))
}

if (wallet.type === WalletType.WALLETCONNECT) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const NavbarWalletMenu = (props: NavbarWalletMenuProps) => {
const { ...menuProps } = props
const account = useCurrentAccount()
const { disconnect } = useDisconnect()
const copy = useCopyToClipboard()
const [, copy] = useCopyToClipboard()

return (
<Menu
Expand All @@ -28,7 +28,7 @@ const NavbarWalletMenu = (props: NavbarWalletMenuProps) => {
>
<MenuItem
aria-label="Copy wallet address to clipboard"
onClick={() => { copy(account.bech32Address) }}
onClick={() => { copy(account.bech32Address, abbreviateWalletAddress(account.bech32Address)) }}
>
<ListItemDecorator><CopyIcon /></ListItemDecorator>
<ListItemContent>
Expand Down
36 changes: 36 additions & 0 deletions frontend/src/components/lib/Copyable/ErrorButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Button, ButtonProps } from '@mui/joy'

import { CopyIcon } from '@assets/icons/Copy'
import { TickIcon } from '@assets/icons/Tick'
import { getErrorReport } from '@utils/errors'
import { mergeSx } from '@utils/styles'
import { useCopyToClipboard } from '@utils/hooks'

interface CopyableErrorButtonProps<T> extends Omit<ButtonProps, "children" | "onClick"> {
error: T,
}

const CopyableErrorButton = <T,>(props: CopyableErrorButtonProps<T>) => {
const { error, ...buttonProps } = props
const [copied, copy] = useCopyToClipboard()

return (
<Button
size="sm"
variant="plain"
color="neutral"
startDecorator={copied ? <TickIcon fontSize="sm" /> : <CopyIcon fontSize="sm" />}
aria-label="Copy error report to clipboard"
{...buttonProps}
sx={mergeSx({ minHeight: 0, p: 0 }, buttonProps.sx)}
onClick={() => {
const report = getErrorReport(error)
copy(report)
}}
>
{copied ? "Copied error report" : "Copy error report"}
</Button>
)
}

export { CopyableErrorButton, type CopyableErrorButtonProps }
34 changes: 34 additions & 0 deletions frontend/src/components/lib/Copyable/Text/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Typography, TypographyProps } from '@mui/joy'

import { mergeSx } from '@utils/styles'
import { useCopyToClipboard } from '@utils/hooks'

interface CopyableTextProps extends Omit<TypographyProps, "children" | "onClick"> {
text: string,
notificationText?: string,
}

const CopyableText = (props: CopyableTextProps) => {
const { text, notificationText, ...typographyProps } = props
const [, copy] = useCopyToClipboard()

return (
<Typography
onClick={() => {
copy(text, notificationText ?? text)
}}
{...typographyProps}
sx={mergeSx(
{
cursor: "pointer",
py: 1,
},
typographyProps.sx,
)}
>
{text}
</Typography>
)
}

export { CopyableText, type CopyableTextProps}
Loading

0 comments on commit d4b52d7

Please sign in to comment.