diff --git a/frontend/package.json b/frontend/package.json
index fe7e62b..1bf549b 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -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",
diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml
index 70e7a27..f79ba1b 100644
--- a/frontend/pnpm-lock.yaml
+++ b/frontend/pnpm-lock.yaml
@@ -50,6 +50,9 @@ importers:
jdenticon:
specifier: ^3.3.0
version: 3.3.0
+ notistack:
+ specifier: ^3.0.1
+ version: 3.0.1(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
react:
specifier: ^18.3.1
version: 18.3.1
@@ -1582,6 +1585,10 @@ packages:
cliui@6.0.0:
resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==}
+ clsx@1.2.1:
+ resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==}
+ engines: {node: '>=6'}
+
clsx@2.1.1:
resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==}
engines: {node: '>=6'}
@@ -1946,6 +1953,11 @@ packages:
globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
+ goober@2.1.14:
+ resolution: {integrity: sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==}
+ peerDependencies:
+ csstype: ^3.0.10
+
gopd@1.0.1:
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
@@ -2335,6 +2347,13 @@ packages:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
+ notistack@3.0.1:
+ resolution: {integrity: sha512-ntVZXXgSQH5WYfyU+3HfcXuKaapzAJ8fBLQ/G618rn3yvSzEbnOB8ZSOwhX+dAORy/lw+GC2N061JA0+gYWTVA==}
+ engines: {node: '>=12.0.0', npm: '>=6.0.0'}
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+
npm-run-path@5.3.0:
resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -5103,6 +5122,8 @@ snapshots:
strip-ansi: 6.0.1
wrap-ansi: 6.2.0
+ clsx@1.2.1: {}
+
clsx@2.1.1: {}
color-convert@1.9.3:
@@ -5516,6 +5537,10 @@ snapshots:
globrex@0.1.2: {}
+ goober@2.1.14(csstype@3.1.3):
+ dependencies:
+ csstype: 3.1.3
+
gopd@1.0.1:
dependencies:
get-intrinsic: 1.2.4
@@ -5951,6 +5976,15 @@ snapshots:
normalize-path@3.0.0: {}
+ notistack@3.0.1(csstype@3.1.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
+ dependencies:
+ clsx: 1.2.1
+ goober: 2.1.14(csstype@3.1.3)
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ transitivePeerDependencies:
+ - csstype
+
npm-run-path@5.3.0:
dependencies:
path-key: 4.0.0
diff --git a/frontend/src/api/mutations/PlaceBet.ts b/frontend/src/api/mutations/PlaceBet.ts
index e0424f0..8a1e8b4 100644
--- a/frontend/src/api/mutations/PlaceBet.ts
+++ b/frontend/src/api/mutations/PlaceBet.ts
@@ -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: {
@@ -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),
@@ -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
diff --git a/frontend/src/app.tsx b/frontend/src/app.tsx
index 97bb018..938ff36 100644
--- a/frontend/src/app.tsx
+++ b/frontend/src/app.tsx
@@ -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 (
diff --git a/frontend/src/assets/icons/ErrorNotification.tsx b/frontend/src/assets/icons/ErrorNotification.tsx
new file mode 100644
index 0000000..fea3b08
--- /dev/null
+++ b/frontend/src/assets/icons/ErrorNotification.tsx
@@ -0,0 +1,21 @@
+import { SvgIcon, SvgIconProps } from '@mui/joy'
+
+const ErrorNotificationIcon = (props: SvgIconProps) => {
+ const Svg = () => (
+
+
+
+
+
+
+
+ )
+
+ return (
+
+
+
+ )
+}
+
+export { ErrorNotificationIcon }
diff --git a/frontend/src/assets/icons/SuccessNotification.tsx b/frontend/src/assets/icons/SuccessNotification.tsx
new file mode 100644
index 0000000..2638f2a
--- /dev/null
+++ b/frontend/src/assets/icons/SuccessNotification.tsx
@@ -0,0 +1,19 @@
+import { SvgIcon, SvgIconProps } from '@mui/joy'
+
+const SuccessNotificationIcon = (props: SvgIconProps) => {
+ const Svg = () => (
+
+
+
+
+
+ )
+
+ return (
+
+
+
+ )
+}
+
+export { SuccessNotificationIcon }
diff --git a/frontend/src/assets/icons/Tick.tsx b/frontend/src/assets/icons/Tick.tsx
new file mode 100644
index 0000000..7723ce0
--- /dev/null
+++ b/frontend/src/assets/icons/Tick.tsx
@@ -0,0 +1,15 @@
+import { SvgIcon, SvgIconProps } from '@mui/joy'
+
+const TickIcon = (props: SvgIconProps) => {
+ const Svg = () => (
+
+ )
+
+ return (
+
+
+
+ )
+}
+
+export { TickIcon }
diff --git a/frontend/src/assets/icons/WarningNotification.tsx b/frontend/src/assets/icons/WarningNotification.tsx
new file mode 100644
index 0000000..ad54657
--- /dev/null
+++ b/frontend/src/assets/icons/WarningNotification.tsx
@@ -0,0 +1,18 @@
+import { SvgIcon, SvgIconProps } from '@mui/joy'
+
+const WarningNotificationIcon = (props: SvgIconProps) => {
+ const Svg = () => (
+
+
+
+
+ )
+
+ return (
+
+
+
+ )
+}
+
+export { WarningNotificationIcon }
diff --git a/frontend/src/components/common/ConnectionModal/index.tsx b/frontend/src/components/common/ConnectionModal/index.tsx
index b5b486c..6d444f8 100644
--- a/frontend/src/components/common/ConnectionModal/index.tsx
+++ b/frontend/src/components/common/ConnectionModal/index.tsx
@@ -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"
@@ -41,6 +43,7 @@ const supportedWallets: WalletOption[] = [
const ConnectionModal = () => {
const { connectAsync } = useConnect()
+ const notifications = useNotifications()
return (
@@ -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) {
diff --git a/frontend/src/components/common/Navbar/WalletButton/Menu/index.tsx b/frontend/src/components/common/Navbar/WalletButton/Menu/index.tsx
index bc9a80b..1ae8893 100644
--- a/frontend/src/components/common/Navbar/WalletButton/Menu/index.tsx
+++ b/frontend/src/components/common/Navbar/WalletButton/Menu/index.tsx
@@ -14,7 +14,7 @@ const NavbarWalletMenu = (props: NavbarWalletMenuProps) => {
const { ...menuProps } = props
const account = useCurrentAccount()
const { disconnect } = useDisconnect()
- const copy = useCopyToClipboard()
+ const [, copy] = useCopyToClipboard()
return (