Skip to content

Commit

Permalink
Merge pull request #13 from Levana-Protocol/perp-4037/display-bets
Browse files Browse the repository at this point in the history
PERP-4037 | Display bets
  • Loading branch information
lvn-alduin authored Sep 9, 2024
2 parents b396e76 + bdb4180 commit 9c534e5
Show file tree
Hide file tree
Showing 23 changed files with 628 additions and 149 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.

15 changes: 13 additions & 2 deletions frontend/src/api/mutations/PlaceBet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ 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'
import { BALANCE_KEYS } from '@api/queries/NtrnBalance'

interface PlaceBetRequest {
deposit: {
Expand Down Expand Up @@ -50,6 +52,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,9 +63,17 @@ 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)}),
() => queryClient.invalidateQueries({ queryKey: BALANCE_KEYS.address(account.bech32Address)}),
)
},
onError: (err, args) => {
notifications.notifyError(
AppError.withCause(`Failed to bet ${args.ntrnAmount.toFormat(true)}.`, err)
)
},
})
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/queries/NtrnBalance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ const ntrnBalanceQuery = (address: string) => queryOptions({
queryFn: () => fetchNtrnBalance(address),
})

export { ntrnBalanceQuery }
export { ntrnBalanceQuery, BALANCE_KEYS }
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 9c534e5

Please sign in to comment.