merge main
This commit is contained in:
commit
5b8d3eb90b
|
@ -0,0 +1,23 @@
|
|||
import { NOTIFICATION_API } from 'utils/constants'
|
||||
|
||||
export type Notification = {
|
||||
content: string
|
||||
createdAt: string
|
||||
seen: boolean
|
||||
title: string
|
||||
id: number
|
||||
}
|
||||
|
||||
export const fetchNotifications = async (wallet: string, token: string) => {
|
||||
const data = await fetch(`${NOTIFICATION_API}notifications`, {
|
||||
headers: {
|
||||
authorization: token,
|
||||
publickey: wallet,
|
||||
},
|
||||
})
|
||||
const body = await data.json()
|
||||
if (body.error) {
|
||||
throw { error: body.error, status: data.status }
|
||||
}
|
||||
return body as Notification[]
|
||||
}
|
|
@ -15,7 +15,7 @@ const ThemeSwitcher = () => {
|
|||
>
|
||||
{THEMES.map((value) => (
|
||||
<LinkButton
|
||||
className={`whitespace-nowrap font-normal no-underline md:hover:text-th-fgd-1 ${
|
||||
className={`whitespace-nowrap font-normal ${
|
||||
t(value) === theme ? 'text-th-active' : ''
|
||||
}`}
|
||||
onClick={() => setTheme(t(value))}
|
||||
|
|
|
@ -25,6 +25,7 @@ import { useViewport } from 'hooks/useViewport'
|
|||
import { breakpoints } from 'utils/theme'
|
||||
import AccountsButton from './AccountsButton'
|
||||
import useUnownedAccount from 'hooks/useUnownedAccount'
|
||||
import NotificationsButton from './notifications/NotificationsButton'
|
||||
|
||||
const TopBar = () => {
|
||||
const { t } = useTranslation('common')
|
||||
|
@ -118,7 +119,8 @@ const TopBar = () => {
|
|||
>{`${t('deposit')} / ${t('withdraw')}`}</Button>
|
||||
)}
|
||||
{connected ? (
|
||||
<div className="flex items-center pr-4 md:pr-0">
|
||||
<div className="flex items-center">
|
||||
<NotificationsButton />
|
||||
<AccountsButton />
|
||||
<ConnectedMenu />
|
||||
</div>
|
||||
|
|
|
@ -522,7 +522,7 @@ const AccountPage = () => {
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-6 border-t border-th-bkg-3 py-3 pl-6 pr-4 md:col-span-3 md:border-l lg:col-span-2 xl:col-span-1 xl:border-t-0">
|
||||
<div className="col-span-6 border-t border-th-bkg-3 py-3 pl-6 pr-4 md:col-span-3 md:border-l lg:col-span-2 lg:border-l-0 xl:col-span-1 xl:border-l xl:border-t-0">
|
||||
<div id="account-step-seven" className="flex flex-col items-start">
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<Tooltip
|
||||
|
|
|
@ -13,7 +13,7 @@ const ActionsLinkButton = ({
|
|||
}) => {
|
||||
return (
|
||||
<LinkButton
|
||||
className="w-full whitespace-nowrap text-left font-normal no-underline md:hover:text-th-fgd-1"
|
||||
className="w-full whitespace-nowrap text-left font-normal"
|
||||
disabled={!mangoAccount}
|
||||
onClick={onClick}
|
||||
>
|
||||
|
|
|
@ -85,7 +85,7 @@ const Chat = () => {
|
|||
</LinkButton>
|
||||
)}
|
||||
<div className="bg-th-bkg-2 px-3 py-0.5">
|
||||
<LinkButton className="mb-0 text-xxs font-normal no-underline">
|
||||
<LinkButton className="mb-0 text-xxs font-normal">
|
||||
<span className="text-th-fgd-4">Content Policy</span>
|
||||
</LinkButton>
|
||||
</div>
|
||||
|
|
|
@ -368,9 +368,7 @@ const UserSetupModal = ({
|
|||
)}
|
||||
</Button>
|
||||
<LinkButton onClick={onClose}>
|
||||
<span className="text-th-fgd-4 underline md:hover:text-th-fgd-3 md:hover:no-underline">
|
||||
{t('onboarding:skip')}
|
||||
</span>
|
||||
</LinkButton>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -513,9 +511,7 @@ const UserSetupModal = ({
|
|||
)}
|
||||
</Button>
|
||||
<LinkButton onClick={onClose}>
|
||||
<span className="text-th-fgd-4 underline md:hover:text-th-fgd-3 md:hover:no-underline">
|
||||
{t('onboarding:skip')}
|
||||
</span>
|
||||
</LinkButton>
|
||||
</UserSetupTransition>
|
||||
<UserSetupTransition show={depositToken.length === 0}>
|
||||
|
@ -547,40 +543,6 @@ const UserSetupModal = ({
|
|||
</div>
|
||||
) : null}
|
||||
</UserSetupTransition>
|
||||
{/* <UserSetupTransition delay show={showSetupStep === 4}>
|
||||
{showSetupStep === 4 ? (
|
||||
<div className="relative">
|
||||
<h2 className="mb-4 font-display text-3xl tracking-normal md:text-5xl lg:text-6xl">
|
||||
{t('onboarding:your-profile')}
|
||||
</h2>
|
||||
<p className="text-base">{t('onboarding:profile-desc')}</p>
|
||||
{!showEditProfilePic ? (
|
||||
<div className="mt-6 border-t border-th-bkg-3 pt-3">
|
||||
<EditProfileForm
|
||||
onFinish={onClose}
|
||||
onEditProfileImage={() => setShowEditProfilePic(true)}
|
||||
onboarding
|
||||
/>
|
||||
<LinkButton className="mt-6" onClick={onClose}>
|
||||
<span className="text-th-fgd-4 underline md:hover:text-th-fgd-3 md:hover:no-underline">
|
||||
{t('onboarding:skip-finish')}
|
||||
</span>
|
||||
</LinkButton>
|
||||
</div>
|
||||
) : null}
|
||||
<UserSetupTransition show={showEditProfilePic}>
|
||||
<div
|
||||
className="thin-scroll absolute mt-6 w-full overflow-auto border-t border-th-bkg-3 px-2 pt-6"
|
||||
style={{ height: 'calc(100vh - 360px)' }}
|
||||
>
|
||||
<EditNftProfilePic
|
||||
onClose={() => setShowEditProfilePic(false)}
|
||||
/>
|
||||
</div>
|
||||
</UserSetupTransition>
|
||||
</div>
|
||||
) : null}
|
||||
</UserSetupTransition> */}
|
||||
</div>
|
||||
<div className="col-span-1 hidden h-screen lg:block">
|
||||
<ParticlesBackground />
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
import { useCookies } from 'hooks/notifications/useCookies'
|
||||
import { useNotifications } from 'hooks/notifications/useNotifications'
|
||||
import { useMemo, useState } from 'react'
|
||||
import NotificationsDrawer from './NotificationsDrawer'
|
||||
import { useToaster } from 'hooks/notifications/useToaster'
|
||||
import { BellIcon } from '@heroicons/react/20/solid'
|
||||
import { useIsAuthorized } from 'hooks/notifications/useIsAuthorized'
|
||||
|
||||
const NotificationsButton = () => {
|
||||
useCookies()
|
||||
useToaster()
|
||||
const { data, isFetching } = useNotifications()
|
||||
const isAuth = useIsAuthorized()
|
||||
const [showDraw, setShowDraw] = useState(false)
|
||||
|
||||
const notificationCount = useMemo(() => {
|
||||
if (!isAuth && !isFetching) {
|
||||
return 1
|
||||
} else if (!data || !data.length) {
|
||||
return 0
|
||||
} else return data.filter((x) => !x.seen).length
|
||||
}, [data, isAuth, isFetching])
|
||||
|
||||
const toggleModal = () => {
|
||||
setShowDraw(!showDraw)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="relative flex h-16 w-16 items-center justify-center border-l border-r border-th-bkg-3 focus-visible:bg-th-bkg-3 md:border-r-0 md:hover:bg-th-bkg-2"
|
||||
onClick={() => toggleModal()}
|
||||
>
|
||||
<BellIcon className="h-5 w-5" />
|
||||
<span className="sr-only">Notifications</span>
|
||||
{notificationCount !== 0 ? (
|
||||
<div className="absolute top-4 right-4">
|
||||
<span className="relative flex h-3.5 w-3.5 items-center justify-center">
|
||||
<span className="absolute inline-flex h-3.5 w-3.5 animate-ping rounded-full bg-th-down opacity-75"></span>
|
||||
<span className="relative flex h-3.5 w-3.5 items-center justify-center rounded-full bg-th-down text-xxs font-bold text-th-fgd-1">
|
||||
{notificationCount}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
</button>
|
||||
<NotificationsDrawer isOpen={showDraw} onClose={toggleModal} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotificationsButton
|
|
@ -0,0 +1,282 @@
|
|||
import Button, { IconButton, LinkButton } from '@components/shared/Button'
|
||||
import { Dialog, Transition } from '@headlessui/react'
|
||||
import {
|
||||
CalendarIcon,
|
||||
FaceSmileIcon,
|
||||
InboxIcon,
|
||||
TrashIcon,
|
||||
XMarkIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import { bs58 } from '@project-serum/anchor/dist/cjs/utils/bytes'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { Payload, SIWS } from '@web3auth/sign-in-with-solana'
|
||||
import { useHeaders } from 'hooks/notifications/useHeaders'
|
||||
import { useIsAuthorized } from 'hooks/notifications/useIsAuthorized'
|
||||
import { useNotifications } from 'hooks/notifications/useNotifications'
|
||||
import { Fragment, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { NOTIFICATION_API } from 'utils/constants'
|
||||
import NotificationCookieStore from '@store/notificationCookieStore'
|
||||
import dayjs from 'dayjs'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import { notify } from 'utils/notifications'
|
||||
|
||||
const NotificationsDrawer = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
}: {
|
||||
isOpen: boolean
|
||||
onClose: () => void
|
||||
}) => {
|
||||
const { t } = useTranslation('notifications')
|
||||
const { data, refetch } = useNotifications()
|
||||
const wallet = useWallet()
|
||||
const isAuth = useIsAuthorized()
|
||||
const headers = useHeaders()
|
||||
const setCookie = NotificationCookieStore((s) => s.setCookie)
|
||||
const [isRemoving, setIsRemoving] = useState(false)
|
||||
|
||||
const unseenNotifications = useMemo(() => {
|
||||
if (!data || !data.length) return []
|
||||
return data.filter((x) => !x.seen)
|
||||
}, [data])
|
||||
|
||||
const markAsSeen = useCallback(
|
||||
async (ids: number[]) => {
|
||||
try {
|
||||
const resp = await fetch(`${NOTIFICATION_API}notifications/seen`, {
|
||||
method: 'POST',
|
||||
headers: headers.headers,
|
||||
body: JSON.stringify({
|
||||
ids: ids,
|
||||
seen: true,
|
||||
}),
|
||||
})
|
||||
const body = await resp.json()
|
||||
const error = body.error
|
||||
if (error) {
|
||||
notify({
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
description: error,
|
||||
})
|
||||
return
|
||||
}
|
||||
refetch()
|
||||
} catch (e) {
|
||||
notify({
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
description: JSON.stringify(e),
|
||||
})
|
||||
}
|
||||
},
|
||||
[NOTIFICATION_API, headers]
|
||||
)
|
||||
|
||||
const remove = useCallback(
|
||||
async (ids: number[]) => {
|
||||
setIsRemoving(true)
|
||||
try {
|
||||
const resp = await fetch(
|
||||
`${NOTIFICATION_API}notifications/removeForUser`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: headers.headers,
|
||||
body: JSON.stringify({
|
||||
ids: ids,
|
||||
}),
|
||||
}
|
||||
)
|
||||
const body = await resp.json()
|
||||
const error = body.error
|
||||
if (error) {
|
||||
notify({
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
description: error,
|
||||
})
|
||||
return
|
||||
}
|
||||
refetch()
|
||||
} catch (e) {
|
||||
notify({
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
description: JSON.stringify(e),
|
||||
})
|
||||
}
|
||||
setIsRemoving(false)
|
||||
},
|
||||
[NOTIFICATION_API, headers]
|
||||
)
|
||||
|
||||
const createSolanaMessage = useCallback(() => {
|
||||
const payload = new Payload()
|
||||
payload.domain = window.location.host
|
||||
payload.address = wallet.publicKey!.toString()
|
||||
payload.uri = window.location.origin
|
||||
payload.statement = 'Login to Mango Notifications Admin App'
|
||||
payload.version = '1'
|
||||
payload.chainId = 1
|
||||
|
||||
const message = new SIWS({ payload })
|
||||
|
||||
const messageText = message.prepareMessage()
|
||||
const messageEncoded = new TextEncoder().encode(messageText)
|
||||
|
||||
wallet.signMessage!(messageEncoded)
|
||||
.then(async (resp) => {
|
||||
const tokenResp = await fetch(`${NOTIFICATION_API}auth`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...payload,
|
||||
signatureString: bs58.encode(resp),
|
||||
}),
|
||||
})
|
||||
const body = await tokenResp.json()
|
||||
const token = body.token
|
||||
const error = body.error
|
||||
if (error) {
|
||||
notify({
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
description: error,
|
||||
})
|
||||
return
|
||||
}
|
||||
setCookie(payload.address, token)
|
||||
})
|
||||
.catch((e) => {
|
||||
notify({
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
description: e.message ? e.message : `${e}`,
|
||||
})
|
||||
})
|
||||
}, [window.location, wallet, NOTIFICATION_API])
|
||||
|
||||
// Mark all notifications as seen when the inbox is opened
|
||||
useEffect(() => {
|
||||
if (isOpen && unseenNotifications?.length) {
|
||||
markAsSeen([...unseenNotifications.map((x) => x.id)])
|
||||
}
|
||||
}, [isOpen, unseenNotifications])
|
||||
|
||||
return (
|
||||
<Transition show={isOpen}>
|
||||
<Dialog className="fixed inset-0 left-0 z-30" onClose={onClose}>
|
||||
<Transition.Child
|
||||
enter="transition-opacity ease-linear duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="transition-opacity ease-linear duration-300"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
as={Fragment}
|
||||
>
|
||||
<div className="fixed inset-0 z-40 cursor-default bg-black bg-opacity-30" />
|
||||
</Transition.Child>
|
||||
<Transition.Child
|
||||
enter="transition ease-in duration-300"
|
||||
enterFrom="translate-x-full"
|
||||
enterTo="translate-x-0"
|
||||
leave="transition ease-out duration-300"
|
||||
leaveFrom="translate-x-0"
|
||||
leaveTo="translate-x-full"
|
||||
as={Fragment}
|
||||
>
|
||||
<Dialog.Panel
|
||||
className={`thin-scroll absolute right-0 z-40 h-full w-full overflow-y-auto bg-th-bkg-1 text-left md:w-96`}
|
||||
>
|
||||
<div className="flex h-16 items-center justify-between border-b border-th-bkg-3 pl-6">
|
||||
<h2 className="text-lg">{t('notifications')}</h2>
|
||||
<div className="flex items-center">
|
||||
{data?.length ? (
|
||||
<LinkButton
|
||||
disabled={isRemoving}
|
||||
className="mr-4 flex items-center text-xs"
|
||||
onClick={() => remove(data.map((n) => n.id))}
|
||||
>
|
||||
<TrashIcon className="mr-1 h-3 w-3" />
|
||||
<span>{t('clear-all')}</span>
|
||||
</LinkButton>
|
||||
) : null}
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="flex h-16 w-16 items-center justify-center border-l border-th-bkg-3 text-th-fgd-3 focus-visible:bg-th-bkg-3 md:hover:bg-th-bkg-2"
|
||||
>
|
||||
<XMarkIcon className={`h-5 w-5`} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{isAuth ? (
|
||||
<>
|
||||
{data?.length ? (
|
||||
<>
|
||||
<div className="space-y-4 border-b border-th-bkg-3 pb-4">
|
||||
{data?.map((notification) => (
|
||||
<div
|
||||
className="border-t border-th-bkg-3 pt-4 first:border-t-0"
|
||||
key={notification.id}
|
||||
>
|
||||
<div className="px-6">
|
||||
<div className="mb-1 flex items-start justify-between">
|
||||
<h4 className="mr-4">{notification.title}</h4>
|
||||
<IconButton
|
||||
disabled={isRemoving}
|
||||
onClick={() => remove([notification.id])}
|
||||
className="mt-1 text-th-fgd-3"
|
||||
hideBg
|
||||
>
|
||||
<TrashIcon className="h-4 w-4" />
|
||||
</IconButton>
|
||||
</div>
|
||||
<div className="mb-2 flex items-center text-th-fgd-4">
|
||||
<CalendarIcon className="mr-1 h-3.5 w-3.5" />
|
||||
<p className="text-xs">
|
||||
{dayjs(notification.createdAt).format(
|
||||
'DD MMM YYYY, h:mma'
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<p>{notification.content}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="relative top-1/2 flex -translate-y-1/2 flex-col justify-center px-6 pb-20">
|
||||
<div className="flex flex-col items-center justify-center text-center">
|
||||
<FaceSmileIcon className="mb-2 h-7 w-7 text-th-fgd-2" />
|
||||
<h3 className="mb-1 text-base">
|
||||
{t('empty-state-title')}
|
||||
</h3>
|
||||
<p>{t('empty-state-desc')}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div className="relative top-1/2 flex -translate-y-1/2 flex-col justify-center px-6 pb-20">
|
||||
<div className="flex flex-col items-center justify-center text-center">
|
||||
<InboxIcon className="mb-2 h-7 w-7 text-th-fgd-2" />
|
||||
<h3 className="mb-1 text-base">{t('unauth-title')}</h3>
|
||||
<p>{t('unauth-desc')}</p>
|
||||
<Button className="mt-6" onClick={createSolanaMessage}>
|
||||
{t('sign-message')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</Dialog>
|
||||
</Transition>
|
||||
)
|
||||
}
|
||||
|
||||
export default NotificationsDrawer
|
|
@ -7,8 +7,8 @@ import {
|
|||
XMarkIcon,
|
||||
} from '@heroicons/react/20/solid'
|
||||
import mangoStore, { CLUSTER } from '@store/mangoStore'
|
||||
import { Notification, notify } from '../../utils/notifications'
|
||||
import Loading from './Loading'
|
||||
import { TransactionNotification, notify } from '../../utils/notifications'
|
||||
import Loading from '@components/shared/Loading'
|
||||
import { Transition } from '@headlessui/react'
|
||||
import {
|
||||
CLIENT_TX_TIMEOUT,
|
||||
|
@ -22,9 +22,9 @@ import { EXPLORERS } from '@components/settings/PreferredExplorerSettings'
|
|||
|
||||
const setMangoStore = mangoStore.getState().set
|
||||
|
||||
const NotificationList = () => {
|
||||
const TransactionNotificationList = () => {
|
||||
const { t } = useTranslation()
|
||||
const notifications = mangoStore((s) => s.notifications)
|
||||
const transactionNotifications = mangoStore((s) => s.transactionNotifications)
|
||||
const walletTokens = mangoStore((s) => s.wallet.tokens)
|
||||
const notEnoughSoLMessage = t('deposit-more-sol')
|
||||
const [notificationPosition] = useLocalStorageState(
|
||||
|
@ -37,11 +37,11 @@ const NotificationList = () => {
|
|||
// if a notification is shown with {"InstructionError":[0,{"Custom":1}]} then
|
||||
// add a notification letting the user know they may not have enough SOL
|
||||
useEffect(() => {
|
||||
if (notifications.length) {
|
||||
const customErrorNotification = notifications.find(
|
||||
if (transactionNotifications.length) {
|
||||
const customErrorNotification = transactionNotifications.find(
|
||||
(n) => n.description && n.description.includes('"Custom":1')
|
||||
)
|
||||
const notEnoughSolNotification = notifications.find(
|
||||
const notEnoughSolNotification = transactionNotifications.find(
|
||||
(n) => n.title && n.title.includes(notEnoughSoLMessage)
|
||||
)
|
||||
|
||||
|
@ -56,19 +56,19 @@ const NotificationList = () => {
|
|||
})
|
||||
}
|
||||
}
|
||||
}, [notifications, walletTokens, maxSolDeposit])
|
||||
}, [transactionNotifications, walletTokens, maxSolDeposit])
|
||||
|
||||
const clearAll = useCallback(() => {
|
||||
setMangoStore((s) => {
|
||||
const newNotifications = s.notifications.map((n) => ({
|
||||
const newNotifications = s.transactionNotifications.map((n) => ({
|
||||
...n,
|
||||
show: false,
|
||||
}))
|
||||
s.notifications = newNotifications
|
||||
s.transactionNotifications = newNotifications
|
||||
})
|
||||
}, [notifications])
|
||||
}, [transactionNotifications])
|
||||
|
||||
const reversedNotifications = [...notifications].reverse()
|
||||
const reversedNotifications = [...transactionNotifications].reverse()
|
||||
|
||||
const getPosition = (position: string) => {
|
||||
const sharedClasses =
|
||||
|
@ -92,7 +92,7 @@ const NotificationList = () => {
|
|||
|
||||
return (
|
||||
<div className={`${getPosition(notificationPosition)} w-full sm:w-auto`}>
|
||||
{notifications.filter((n) => n.show).length > 1 ? (
|
||||
{transactionNotifications.filter((n) => n.show).length > 1 ? (
|
||||
<button
|
||||
className="pointer-events-auto my-1 flex items-center rounded bg-th-bkg-3 px-2 py-1 text-xs text-th-fgd-3 md:hover:bg-th-bkg-4"
|
||||
onClick={clearAll}
|
||||
|
@ -102,13 +102,17 @@ const NotificationList = () => {
|
|||
</button>
|
||||
) : null}
|
||||
{reversedNotifications.map((n) => (
|
||||
<Notification key={n.id} notification={n} />
|
||||
<TransactionNotification key={n.id} notification={n} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Notification = ({ notification }: { notification: Notification }) => {
|
||||
const TransactionNotification = ({
|
||||
notification,
|
||||
}: {
|
||||
notification: TransactionNotification
|
||||
}) => {
|
||||
const [notificationPosition] = useLocalStorageState(
|
||||
NOTIFICATION_POSITION_KEY,
|
||||
'Bottom-Left'
|
||||
|
@ -141,20 +145,20 @@ const Notification = ({ notification }: { notification: Notification }) => {
|
|||
useEffect(() => {
|
||||
if ((type === 'error' || type === 'success') && txid) {
|
||||
setMangoStore((s) => {
|
||||
const newNotifications = s.notifications.map((n) =>
|
||||
const newNotifications = s.transactionNotifications.map((n) =>
|
||||
n.txid === txid && n.type === 'confirm' ? { ...n, show: false } : n
|
||||
)
|
||||
s.notifications = newNotifications
|
||||
s.transactionNotifications = newNotifications
|
||||
})
|
||||
}
|
||||
}, [type, txid])
|
||||
|
||||
const hideNotification = () => {
|
||||
setMangoStore((s) => {
|
||||
const newNotifications = s.notifications.map((n) =>
|
||||
const newNotifications = s.transactionNotifications.map((n) =>
|
||||
n.id === id ? { ...n, show: false } : n
|
||||
)
|
||||
s.notifications = newNotifications
|
||||
s.transactionNotifications = newNotifications
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -302,4 +306,4 @@ const Notification = ({ notification }: { notification: Notification }) => {
|
|||
)
|
||||
}
|
||||
|
||||
export default NotificationList
|
||||
export default TransactionNotificationList
|
|
@ -153,7 +153,7 @@ const EditNftProfilePic = ({ onClose }: { onClose: () => void }) => {
|
|||
{t('save')}
|
||||
</Button>
|
||||
{profile?.profile_image_url ? (
|
||||
<LinkButton className="text-sm" onClick={removeProfileImage}>
|
||||
<LinkButton onClick={removeProfileImage}>
|
||||
{t('profile:remove')}
|
||||
</LinkButton>
|
||||
) : null}
|
||||
|
|
|
@ -324,7 +324,7 @@ const Balance = ({ bank }: { bank: BankWithBalance }) => {
|
|||
{!isUnownedAccount ? (
|
||||
asPath.includes('/trade') && isBaseOrQuote ? (
|
||||
<LinkButton
|
||||
className="font-normal underline-offset-2 md:underline-offset-4"
|
||||
className="font-normal underline underline-offset-2 md:underline-offset-4 md:hover:no-underline"
|
||||
onClick={() =>
|
||||
handleTradeFormBalanceClick(Math.abs(balance), isBaseOrQuote)
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ const Balance = ({ bank }: { bank: BankWithBalance }) => {
|
|||
</LinkButton>
|
||||
) : asPath.includes('/swap') ? (
|
||||
<LinkButton
|
||||
className="font-normal underline-offset-2 md:underline-offset-4"
|
||||
className="font-normal underline underline-offset-2 md:underline-offset-4 md:hover:no-underline"
|
||||
onClick={() =>
|
||||
handleSwapFormBalanceClick(
|
||||
Number(formatNumericValue(balance, tokenBank.mintDecimals))
|
||||
|
|
|
@ -114,7 +114,7 @@ export const LinkButton: FunctionComponent<LinkButtonCombinedProps> = ({
|
|||
disabled={disabled}
|
||||
className={`flex items-center border-0 font-bold ${
|
||||
secondary ? 'text-th-active' : 'text-th-fgd-2'
|
||||
} rounded-sm underline focus-visible:text-th-active focus-visible:no-underline disabled:cursor-not-allowed disabled:opacity-50 md:hover:text-th-fgd-3 md:hover:no-underline ${className}`}
|
||||
} rounded-sm focus-visible:text-th-active focus-visible:underline disabled:cursor-not-allowed disabled:opacity-50 ${className} md:hover:text-th-fgd-3`}
|
||||
{...props}
|
||||
type="button"
|
||||
>
|
||||
|
|
|
@ -19,7 +19,7 @@ const MaxAmountButton = ({
|
|||
}) => {
|
||||
return (
|
||||
<LinkButton
|
||||
className={`font-normal no-underline ${className} md:hover:text-th-fgd-3`}
|
||||
className={`font-normal ${className}`}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
>
|
||||
|
|
|
@ -41,14 +41,16 @@ const MangoPerpStatsCharts = () => {
|
|||
if (!hasDate) {
|
||||
a.push({
|
||||
date: c.date_hour,
|
||||
feeValue: c.fees_accrued,
|
||||
feeValue: c.total_fees,
|
||||
})
|
||||
} else {
|
||||
hasDate.feeValue = hasDate.feeValue + c.fees_accrued
|
||||
hasDate.feeValue = hasDate.feeValue + c.total_fees
|
||||
}
|
||||
return a
|
||||
return a.sort(
|
||||
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
|
||||
)
|
||||
}, [])
|
||||
return values.reverse()
|
||||
return values
|
||||
}, [perpStats])
|
||||
|
||||
const totalOpenInterestValues = useMemo(() => {
|
||||
|
@ -64,9 +66,11 @@ const MangoPerpStatsCharts = () => {
|
|||
hasDate.openInterest =
|
||||
hasDate.openInterest + Math.floor(c.open_interest * c.price)
|
||||
}
|
||||
return a
|
||||
return a.sort(
|
||||
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
|
||||
)
|
||||
}, [])
|
||||
return values.reverse()
|
||||
return values
|
||||
}, [perpStats])
|
||||
|
||||
return (
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
} from '@heroicons/react/20/solid'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import Image from 'next/legacy/image'
|
||||
import { useEffect } from 'react'
|
||||
import { useViewport } from '../../hooks/useViewport'
|
||||
import { breakpoints } from '../../utils/theme'
|
||||
import { LinkButton } from '../shared/Button'
|
||||
|
@ -17,7 +16,6 @@ import { NextRouter, useRouter } from 'next/router'
|
|||
import useJupiterMints from 'hooks/useJupiterMints'
|
||||
import { Table, Td, Th, TrBody, TrHead } from '@components/shared/TableElements'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import FormatNumericValue from '@components/shared/FormatNumericValue'
|
||||
import BankAmountWithValue from '@components/shared/BankAmountWithValue'
|
||||
import useBanksWithBalances from 'hooks/useBanksWithBalances'
|
||||
|
@ -25,8 +23,6 @@ import Decimal from 'decimal.js'
|
|||
|
||||
const TokenStats = () => {
|
||||
const { t } = useTranslation(['common', 'token'])
|
||||
const actions = mangoStore.getState().actions
|
||||
const initialStatsLoad = mangoStore((s) => s.tokenStats.initialLoad)
|
||||
const { group } = useMangoGroup()
|
||||
const { mangoTokens } = useJupiterMints()
|
||||
const { width } = useViewport()
|
||||
|
@ -34,18 +30,6 @@ const TokenStats = () => {
|
|||
const router = useRouter()
|
||||
const banks = useBanksWithBalances()
|
||||
|
||||
useEffect(() => {
|
||||
if (group && !initialStatsLoad) {
|
||||
actions.fetchTokenStats()
|
||||
}
|
||||
}, [group])
|
||||
|
||||
// const goToTokenPage = (bank: Bank) => {
|
||||
// router.push(`/token/${bank.name.split(' ')[0].toUpperCase()}`, undefined, {
|
||||
// shallow: true,
|
||||
// })
|
||||
// }
|
||||
|
||||
const goToTokenPage = (token: string, router: NextRouter) => {
|
||||
const query = { ...router.query, ['token']: token }
|
||||
router.push({ pathname: router.pathname, query })
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import mangoStore from '@store/mangoStore'
|
||||
import { useTranslation } from 'next-i18next'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import { formatYAxis } from 'utils/formatting'
|
||||
import useBanksWithBalances from 'hooks/useBanksWithBalances'
|
||||
import { TokenStatsItem } from 'types'
|
||||
import useMangoGroup from 'hooks/useMangoGroup'
|
||||
const DetailedAreaChart = dynamic(
|
||||
() => import('@components/shared/DetailedAreaChart'),
|
||||
{ ssr: false }
|
||||
|
@ -19,12 +20,21 @@ interface TotalValueItem {
|
|||
|
||||
const TotalDepositBorrowCharts = () => {
|
||||
const { t } = useTranslation(['common', 'token', 'trade'])
|
||||
const { group } = useMangoGroup()
|
||||
const tokenStats = mangoStore((s) => s.tokenStats.data)
|
||||
const initialStatsLoad = mangoStore((s) => s.tokenStats.initialLoad)
|
||||
const loadingStats = mangoStore((s) => s.tokenStats.loading)
|
||||
const [borrowDaysToShow, setBorrowDaysToShow] = useState('30')
|
||||
const [depositDaysToShow, setDepositDaysToShow] = useState('30')
|
||||
const banks = useBanksWithBalances()
|
||||
|
||||
useEffect(() => {
|
||||
if (group && !initialStatsLoad) {
|
||||
const actions = mangoStore.getState().actions
|
||||
actions.fetchTokenStats()
|
||||
}
|
||||
}, [group, initialStatsLoad])
|
||||
|
||||
const totalDepositBorrowValues = useMemo(() => {
|
||||
if (!tokenStats) return []
|
||||
const values: TotalValueItem[] = tokenStats.reduce(
|
||||
|
@ -42,11 +52,13 @@ const TotalDepositBorrowCharts = () => {
|
|||
hasDate.borrowValue =
|
||||
hasDate.borrowValue + Math.floor(c.total_borrows * c.price)
|
||||
}
|
||||
return a
|
||||
return a.sort(
|
||||
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
|
||||
)
|
||||
},
|
||||
[]
|
||||
)
|
||||
return values.reverse()
|
||||
return values
|
||||
}, [tokenStats])
|
||||
|
||||
const [currentTotalDepositValue, currentTotalBorrowValue] = useMemo(() => {
|
||||
|
|
|
@ -204,7 +204,7 @@ const AdvancedMarketHeader = ({
|
|||
<div className="ml-6 flex items-center space-x-4">
|
||||
{selectedMarket instanceof PerpMarket ? (
|
||||
<LinkButton
|
||||
className="flex items-center whitespace-nowrap text-th-fgd-3 no-underline md:hover:text-th-fgd-4"
|
||||
className="flex items-center whitespace-nowrap text-th-fgd-3"
|
||||
onClick={() => setShowMarketDetails(true)}
|
||||
>
|
||||
<InformationCircleIcon className="h-5 w-5 flex-shrink-0 md:mr-1.5 md:h-4 md:w-4" />
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useMemo } from 'react'
|
||||
import React, { useCallback, useMemo } from 'react'
|
||||
import { Listbox } from '@headlessui/react'
|
||||
import { ChevronDownIcon } from '@heroicons/react/20/solid'
|
||||
import Decimal from 'decimal.js'
|
||||
|
||||
const GroupSize = ({
|
||||
tickSize,
|
||||
|
@ -13,13 +14,20 @@ const GroupSize = ({
|
|||
onChange: (x: number) => void
|
||||
className?: string
|
||||
}) => {
|
||||
const formatSize = useCallback(
|
||||
(multiplier: number) => {
|
||||
return new Decimal(tickSize).mul(multiplier).toNumber()
|
||||
},
|
||||
[tickSize]
|
||||
)
|
||||
|
||||
const sizes = useMemo(
|
||||
() => [
|
||||
tickSize,
|
||||
tickSize * 5,
|
||||
tickSize * 10,
|
||||
tickSize * 50,
|
||||
tickSize * 100,
|
||||
formatSize(5),
|
||||
formatSize(10),
|
||||
formatSize(50),
|
||||
formatSize(100),
|
||||
],
|
||||
[tickSize]
|
||||
)
|
||||
|
|
|
@ -204,7 +204,7 @@ const MarketCloseModal: FunctionComponent<MarketCloseModalProps> = ({
|
|||
{submitting ? <Loading /> : <span>{t('trade:close-position')}</span>}
|
||||
</Button>
|
||||
<LinkButton
|
||||
className="inline-flex w-full items-center justify-center text-th-fgd-1"
|
||||
className="inline-flex w-full items-center justify-center"
|
||||
onClick={onClose}
|
||||
>
|
||||
{t('cancel')}
|
||||
|
|
|
@ -149,6 +149,7 @@ const PerpPositions = () => {
|
|||
<p className="flex justify-end">
|
||||
{isSelectedMarket ? (
|
||||
<LinkButton
|
||||
className="font-normal underline underline-offset-2 md:underline-offset-4 md:hover:no-underline"
|
||||
onClick={() =>
|
||||
handlePositionClick(floorBasePosition, market)
|
||||
}
|
||||
|
@ -294,7 +295,7 @@ const PerpPositions = () => {
|
|||
<span className="font-mono text-th-fgd-3">
|
||||
{isSelectedMarket && asPath === '/trade' ? (
|
||||
<LinkButton
|
||||
className="font-normal"
|
||||
className="font-normal underline underline-offset-2 md:underline-offset-4 md:hover:no-underline"
|
||||
onClick={() =>
|
||||
handlePositionClick(floorBasePosition, market)
|
||||
}
|
||||
|
|
|
@ -76,11 +76,14 @@ const ConnectedMenu = () => {
|
|||
<Popover>
|
||||
<div className="relative">
|
||||
<Popover.Button
|
||||
className={`h-16 ${
|
||||
!isMobile ? 'w-48 border-l border-th-bkg-3 px-4' : ''
|
||||
} focus:outline-none focus-visible:bg-th-bkg-3 md:hover:bg-th-bkg-2`}
|
||||
className={`default-transition h-16 ${
|
||||
!isMobile ? 'w-48 border-l border-th-bkg-3 px-4' : 'w-16'
|
||||
} hover:bg-th-bkg-2 focus:outline-none focus-visible:bg-th-bkg-3`}
|
||||
>
|
||||
<div
|
||||
className="flex items-center justify-center md:justify-start"
|
||||
id="account-step-one"
|
||||
>
|
||||
<div className="flex items-center" id="account-step-one">
|
||||
<ProfileImage
|
||||
imageSize="40"
|
||||
placeholderSize="24"
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import NotificationCookieStore from '@store/notificationCookieStore'
|
||||
import { useEffect } from 'react'
|
||||
import { useNotifications } from './useNotifications'
|
||||
import { notify } from 'utils/notifications'
|
||||
|
||||
type Error = {
|
||||
status: number
|
||||
error: string
|
||||
}
|
||||
|
||||
export function useCookies() {
|
||||
const wallet = useWallet()
|
||||
const updateCookie = NotificationCookieStore((s) => s.updateCookie)
|
||||
const removeCookie = NotificationCookieStore((s) => s.removeCookie)
|
||||
const token = NotificationCookieStore((s) => s.currentToken)
|
||||
const { error } = useNotifications()
|
||||
const errorResp = error as Error
|
||||
|
||||
useEffect(() => {
|
||||
updateCookie(wallet.publicKey?.toBase58())
|
||||
}, [wallet.publicKey?.toBase58()])
|
||||
|
||||
useEffect(() => {
|
||||
if (errorResp?.status === 401 && wallet.publicKey && token) {
|
||||
removeCookie(wallet.publicKey?.toBase58())
|
||||
notify({
|
||||
title: errorResp.error,
|
||||
type: 'error',
|
||||
})
|
||||
}
|
||||
}, [errorResp, wallet.publicKey?.toBase58()])
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import NotificationCookieStore from '@store/notificationCookieStore'
|
||||
|
||||
export function useHeaders() {
|
||||
const { publicKey } = useWallet()
|
||||
const token = NotificationCookieStore((s) => s.currentToken)
|
||||
|
||||
return {
|
||||
headers: {
|
||||
authorization: token,
|
||||
publickey: publicKey?.toBase58() || '',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
import { useNotifications } from './useNotifications'
|
||||
import NotificationCookieStore from '@store/notificationCookieStore'
|
||||
|
||||
export function useIsAuthorized() {
|
||||
const wallet = useWallet()
|
||||
const { error, isFetched, isLoading } = useNotifications()
|
||||
const walletPubKey = wallet.publicKey?.toBase58()
|
||||
const token = NotificationCookieStore((s) => s.currentToken)
|
||||
|
||||
const isAuthorized =
|
||||
walletPubKey && token && !error && isFetched && !isLoading
|
||||
|
||||
return isAuthorized
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
import { useQuery } from '@tanstack/react-query'
|
||||
import { fetchNotifications } from 'apis/notifications'
|
||||
import NotificationCookieStore from '@store/notificationCookieStore'
|
||||
import { useWallet } from '@solana/wallet-adapter-react'
|
||||
|
||||
//10min
|
||||
const refetchMs = 600000
|
||||
|
||||
export function useNotifications() {
|
||||
const wallet = useWallet()
|
||||
const walletPubKey = wallet.publicKey?.toBase58()
|
||||
const token = NotificationCookieStore((s) => s.currentToken)
|
||||
const criteria = `${walletPubKey}${token}`
|
||||
|
||||
return useQuery(
|
||||
['notifications', criteria],
|
||||
() => fetchNotifications(walletPubKey!, token!),
|
||||
{
|
||||
enabled: !!(walletPubKey && token),
|
||||
staleTime: refetchMs,
|
||||
retry: 1,
|
||||
refetchInterval: refetchMs,
|
||||
}
|
||||
)
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import usePrevious from '@components/shared/usePrevious'
|
||||
import { useNotifications } from './useNotifications'
|
||||
import { useEffect } from 'react'
|
||||
import { Notification } from '../../apis/notifications'
|
||||
import { notify } from 'utils/notifications'
|
||||
|
||||
export function useToaster() {
|
||||
const { data } = useNotifications()
|
||||
const previousData = usePrevious(data)
|
||||
|
||||
useEffect(() => {
|
||||
if (data && data.length && previousData) {
|
||||
const oldIds = previousData.map((item: Notification) => item.id)
|
||||
const newObjects = data.filter(
|
||||
(item: Notification) => !oldIds.includes(item.id)
|
||||
)
|
||||
if (newObjects.length) {
|
||||
newObjects.map((x) =>
|
||||
notify({
|
||||
title: 'New message',
|
||||
description: x.title,
|
||||
type: 'info',
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
}, [data, previousData])
|
||||
}
|
|
@ -34,6 +34,7 @@
|
|||
"@tippyjs/react": "4.2.6",
|
||||
"@types/howler": "2.2.7",
|
||||
"@types/lodash": "4.14.185",
|
||||
"@web3auth/sign-in-with-solana": "1.0.0",
|
||||
"assert": "2.0.0",
|
||||
"big.js": "6.2.1",
|
||||
"clsx": "1.2.1",
|
||||
|
@ -46,6 +47,7 @@
|
|||
"html2canvas": "1.4.1",
|
||||
"http-proxy-middleware": "2.0.6",
|
||||
"immer": "9.0.12",
|
||||
"js-cookie": "3.0.1",
|
||||
"klinecharts": "8.6.3",
|
||||
"lodash": "4.17.21",
|
||||
"next": "13.1.0",
|
||||
|
@ -76,6 +78,7 @@
|
|||
"@types/big.js": "6.1.6",
|
||||
"@types/node": "17.0.23",
|
||||
"@types/react": "18.0.3",
|
||||
"@types/js-cookie": "3.0.3",
|
||||
"@types/react-dom": "18.0.0",
|
||||
"@types/react-grid-layout": "1.3.2",
|
||||
"@types/react-window": "1.8.5",
|
||||
|
|
|
@ -7,6 +7,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
props: {
|
||||
...(await serverSideTranslations(locale, [
|
||||
'common',
|
||||
'notifications',
|
||||
'profile',
|
||||
'search',
|
||||
'settings',
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
GlowWalletAdapter,
|
||||
} from '@solana/wallet-adapter-wallets'
|
||||
import { clusterApiUrl } from '@solana/web3.js'
|
||||
import Notifications from '../components/shared/Notification'
|
||||
import TransactionNotification from '@components/notifications/TransactionNotification'
|
||||
import { ThemeProvider } from 'next-themes'
|
||||
import { appWithTranslation } from 'next-i18next'
|
||||
import Layout from '../components/Layout'
|
||||
|
@ -118,7 +118,7 @@ function MyApp({ Component, pageProps }: AppProps) {
|
|||
<Component {...pageProps} />
|
||||
</Layout>
|
||||
</ViewportProvider>
|
||||
<Notifications />
|
||||
<TransactionNotification />
|
||||
</ThemeProvider>
|
||||
</EnhancedWalletProvider>
|
||||
</WalletProvider>
|
||||
|
|
|
@ -8,6 +8,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
...(await serverSideTranslations(locale, [
|
||||
'borrow',
|
||||
'common',
|
||||
'notifications',
|
||||
'onboarding',
|
||||
'profile',
|
||||
'search',
|
||||
|
|
|
@ -27,6 +27,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
props: {
|
||||
...(await serverSideTranslations(locale, [
|
||||
'common',
|
||||
'notifications',
|
||||
'onboarding',
|
||||
'profile',
|
||||
'search',
|
||||
|
|
|
@ -10,11 +10,12 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(locale, [
|
||||
'governance',
|
||||
'search',
|
||||
'common',
|
||||
'governance',
|
||||
'notifications',
|
||||
'onboarding',
|
||||
'profile',
|
||||
'search',
|
||||
])),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -8,11 +8,12 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
return {
|
||||
props: {
|
||||
...(await serverSideTranslations(locale, [
|
||||
'governance',
|
||||
'search',
|
||||
'common',
|
||||
'governance',
|
||||
'notifications',
|
||||
'onboarding',
|
||||
'profile',
|
||||
'search',
|
||||
])),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
'account',
|
||||
'activity',
|
||||
'common',
|
||||
'notifications',
|
||||
'onboarding',
|
||||
'onboarding-tours',
|
||||
'profile',
|
||||
|
|
|
@ -8,6 +8,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
...(await serverSideTranslations(locale, [
|
||||
'common',
|
||||
'leaderboard',
|
||||
'notifications',
|
||||
'profile',
|
||||
'search',
|
||||
])),
|
||||
|
|
|
@ -7,6 +7,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
props: {
|
||||
...(await serverSideTranslations(locale, [
|
||||
'common',
|
||||
'notifications',
|
||||
'profile',
|
||||
'search',
|
||||
])),
|
||||
|
|
|
@ -12,6 +12,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
props: {
|
||||
...(await serverSideTranslations(locale, [
|
||||
'common',
|
||||
'notifications',
|
||||
'onboarding',
|
||||
'profile',
|
||||
'search',
|
||||
|
|
|
@ -7,6 +7,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
props: {
|
||||
...(await serverSideTranslations(locale, [
|
||||
'common',
|
||||
'notifications',
|
||||
'onboarding',
|
||||
'profile',
|
||||
'search',
|
||||
|
|
|
@ -7,6 +7,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
props: {
|
||||
...(await serverSideTranslations(locale, [
|
||||
'common',
|
||||
'notifications',
|
||||
'onboarding',
|
||||
'onboarding-tours',
|
||||
'profile',
|
||||
|
|
|
@ -16,6 +16,7 @@ export async function getStaticProps({ locale }: { locale: string }) {
|
|||
props: {
|
||||
...(await serverSideTranslations(locale, [
|
||||
'common',
|
||||
'notifications',
|
||||
'onboarding',
|
||||
'onboarding-tours',
|
||||
'profile',
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"clear-all": "Clear All",
|
||||
"empty-state-desc": "You're all up-to-date",
|
||||
"empty-state-title": "Nothing to see here",
|
||||
"notifications": "Notifications",
|
||||
"sign-message": "Sign Message",
|
||||
"unauth-desc": "You need to verify your wallet to start receiving notifications.",
|
||||
"unauth-title": "Notifications Inbox"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"clear-all": "Clear All",
|
||||
"empty-state-desc": "You're all up-to-date",
|
||||
"empty-state-title": "Nothing to see here",
|
||||
"notifications": "Notifications",
|
||||
"sign-message": "Sign Message",
|
||||
"unauth-desc": "You need to verify your wallet to start receiving notifications.",
|
||||
"unauth-title": "Notifications Inbox"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"clear-all": "Clear All",
|
||||
"empty-state-desc": "You're all up-to-date",
|
||||
"empty-state-title": "Nothing to see here",
|
||||
"notifications": "Notifications",
|
||||
"sign-message": "Sign Message",
|
||||
"unauth-desc": "You need to verify your wallet to start receiving notifications.",
|
||||
"unauth-title": "Notifications Inbox"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"clear-all": "Clear All",
|
||||
"empty-state-desc": "You're all up-to-date",
|
||||
"empty-state-title": "Nothing to see here",
|
||||
"notifications": "Notifications",
|
||||
"sign-message": "Sign Message",
|
||||
"unauth-desc": "You need to verify your wallet to start receiving notifications.",
|
||||
"unauth-title": "Notifications Inbox"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"clear-all": "Clear All",
|
||||
"empty-state-desc": "You're all up-to-date",
|
||||
"empty-state-title": "Nothing to see here",
|
||||
"notifications": "Notifications",
|
||||
"sign-message": "Sign Message",
|
||||
"unauth-desc": "You need to verify your wallet to start receiving notifications.",
|
||||
"unauth-title": "Notifications Inbox"
|
||||
}
|
|
@ -1,45 +1,51 @@
|
|||
<svg width="985" height="1006" viewBox="0 0 985 1006" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1501_16732)">
|
||||
<path d="M577.996 164.494C511.332 138.229 448.649 139.227 405.047 149.95C519.372 350.391 736.652 216.784 754.428 205.362C713.589 206.589 658.367 196.205 577.996 164.494Z" fill="url(#paint0_linear_1501_16732)"/>
|
||||
<path d="M577 166.289C657.369 198 713.659 206.589 754.467 205.362L755.643 204.604C603.604 -54.75 404.799 149.441 404.799 149.441L405.088 149.95C447.971 142.349 510.295 139.985 577 166.289Z" fill="url(#paint1_linear_1501_16732)"/>
|
||||
<path d="M566.586 652.388C524.691 752.539 444.25 818.854 346.794 828.9C344.698 829.179 318.025 831.283 303.302 830.196C418.894 914.705 555.265 928.82 555.265 928.82C584.461 931.812 617.509 934.266 650.677 933.398C662.356 902.905 668.931 867.992 667.045 828.38C662.666 736.38 716.013 689.147 773.78 664.917C744.173 619.141 722.079 563.7 706.946 511.798C661.839 523.799 604.55 561.535 566.586 652.388Z" fill="url(#paint2_linear_1501_16732)"/>
|
||||
<path d="M665.218 827.73C667.114 867.342 659.173 903.083 647.493 933.578C733.13 931.323 822.737 906.874 845.61 813.825C850.458 794.084 851.076 772.628 843.017 753.975C835.155 735.8 820.004 722.054 806.557 707.511C793.977 693.614 782.571 678.701 772.451 662.922C714.736 687.161 660.84 735.74 665.218 827.73Z" fill="url(#paint3_linear_1501_16732)"/>
|
||||
<path d="M703.962 501.554C690.805 466.342 679.604 431.09 662.577 398.303C656.882 387.237 650.443 376.573 643.305 366.382C626.088 341.981 607.763 318.222 585.737 297.991C547.831 298.101 508.221 291.738 472.021 273.164C435.351 325.175 393.396 413.403 431.8 514.114C488.509 662.843 373.427 764.49 299.57 827.423L303.301 830.196C317.149 831.276 331.066 831.076 344.878 829.597C442.325 819.542 527.423 751.632 569.318 651.491C607.294 560.638 662.536 526.124 707.585 514.114C706.313 509.924 705.108 505.737 703.962 501.554Z" fill="url(#paint4_linear_1501_16732)"/>
|
||||
<path d="M220.976 303.487C164.517 365.333 134.751 452.307 135.779 537.185C136.367 586.573 149.365 633.036 170.692 675.72C173.89 682.124 177.282 688.441 180.866 694.672C299.561 575.529 256.677 398.002 220.976 303.487Z" fill="url(#paint5_linear_1501_16732)"/>
|
||||
<path d="M433.795 514.112C395.391 413.364 436.41 325.713 473.029 273.712C448.88 261.279 427.397 244.245 409.786 223.566C381.255 223.019 352.841 227.362 325.775 236.405C282.603 250.699 246.134 275.807 216.956 307.767C251.869 400.207 293.825 573.864 177.754 690.393C199.799 728.898 228.627 763.97 261.026 794.893C273.805 807.076 287.346 818.435 301.565 828.899C375.421 765.996 490.504 662.842 433.795 514.112Z" fill="url(#paint6_linear_1501_16732)"/>
|
||||
</g>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M472.746 272.289C472.751 272.283 472.755 272.276 472.76 272.27C509.05 290.89 548.76 297.27 586.76 297.16C608.84 317.44 627.21 341.26 644.47 365.72C651.627 375.937 658.082 386.628 663.79 397.72C676.989 423.136 686.696 450.028 696.518 477.237C699.398 485.217 702.289 493.225 705.28 501.23C706.217 504.656 707.196 508.084 708.217 511.514L708.27 511.5C723.44 563.53 745.59 619.11 775.27 665L775.241 665.012C785.058 680.087 796.055 694.361 808.13 707.7C810.506 710.27 812.936 712.816 815.369 715.365L815.37 715.366L815.371 715.367L815.374 715.37C826.742 727.28 838.19 739.274 844.68 754.28C852.76 772.98 852.14 794.49 847.28 814.28C824.35 907.56 734.52 932.07 648.67 934.33L648.711 934.223C616.522 934.864 584.556 932.465 556.21 929.56C556.21 929.56 419.5 915.41 303.62 830.69L299.88 827.91L299.881 827.909C286.355 817.83 273.451 806.941 261.24 795.3C228.76 764.3 199.86 729.14 177.76 690.54C177.908 690.392 178.055 690.243 178.203 690.095C175.587 685.388 173.079 680.633 170.68 675.83C149.3 633.04 136.27 586.46 135.68 536.95C134.674 453.873 163.095 368.795 217.118 307.113C217.098 307.062 217.079 307.011 217.06 306.96C246.31 274.92 282.87 249.75 326.15 235.42C353.283 226.354 381.768 222.001 410.37 222.55C427.775 242.987 448.954 259.874 472.746 272.289ZM406.153 815.85C425.711 808.711 444.24 799.11 461.518 787.279C444.131 799.029 425.575 808.637 406.153 815.85Z" fill="url(#paint0_linear_1501_16722)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M756.498 204.628C756.512 204.628 756.526 204.628 756.54 204.627L757.72 203.867C605.3 -56.1329 406 148.567 406 148.567L406.285 149.068C406.273 149.071 406.262 149.074 406.25 149.077C520.856 350.01 738.664 216.087 756.498 204.628Z" fill="url(#paint1_linear_1501_16722)"/>
|
||||
<path d="M567.56 652.44C525.56 752.84 444.92 819.32 347.22 829.39C345.12 829.67 318.38 831.78 303.62 830.69C419.5 915.41 556.21 929.56 556.21 929.56C585.48 932.56 618.61 935.02 651.86 934.15C663.57 903.58 670.16 868.58 668.27 828.87C663.88 736.64 717.36 689.29 775.27 665C745.59 619.11 723.44 563.53 708.27 511.5C663.05 523.53 605.62 561.36 567.56 652.44Z" fill="url(#paint2_linear_1501_16722)"/>
|
||||
<path d="M666.44 828.22C668.34 867.93 660.38 903.76 648.67 934.33C734.52 932.07 824.35 907.56 847.28 814.28C852.14 794.49 852.76 772.98 844.68 754.28C836.8 736.06 821.61 722.28 808.13 707.7C795.519 693.769 784.084 678.818 773.94 663C716.08 687.3 662.05 736 666.44 828.22Z" fill="url(#paint3_linear_1501_16722)"/>
|
||||
<path d="M705.28 501.23C692.09 465.93 680.86 430.59 663.79 397.72C658.082 386.628 651.627 375.937 644.47 365.72C627.21 341.26 608.84 317.44 586.76 297.16C548.76 297.27 509.05 290.89 472.76 272.27C436 324.41 393.94 412.86 432.44 513.82C489.29 662.92 373.92 764.82 299.88 827.91L303.62 830.69C317.502 831.773 331.455 831.573 345.3 830.09C442.99 820.01 528.3 751.93 570.3 651.54C608.37 560.46 663.75 525.86 708.91 513.82C707.637 509.62 706.427 505.423 705.28 501.23Z" fill="url(#paint4_linear_1501_16722)"/>
|
||||
<path d="M221.09 302.67C164.49 364.67 134.65 451.86 135.68 536.95C136.27 586.46 149.3 633.04 170.68 675.83C173.887 682.25 177.287 688.583 180.88 694.83C299.87 575.39 256.88 397.42 221.09 302.67Z" fill="url(#paint5_linear_1501_16722)"/>
|
||||
<path d="M434.44 513.82C395.94 412.82 437.06 324.95 473.77 272.82C449.561 260.357 428.024 243.28 410.37 222.55C381.768 222.001 353.283 226.354 326.15 235.42C282.87 249.75 246.31 274.92 217.06 306.96C252.06 399.63 294.12 573.72 177.76 690.54C199.86 729.14 228.76 764.3 261.24 795.3C274.051 807.513 287.625 818.899 301.88 829.39C375.92 766.33 491.29 662.92 434.44 513.82Z" fill="url(#paint6_linear_1501_16722)"/>
|
||||
<path d="M578 165.13C658.57 196.92 715 205.53 755.91 204.3L757.09 203.54C604.67 -56.4601 405.37 148.24 405.37 148.24L405.66 148.75C448.65 141.13 511.13 138.76 578 165.13Z" fill="url(#paint7_linear_1501_16722)"/>
|
||||
<path d="M579 163.33C512.17 137 449.33 138 405.62 148.75C520.23 349.69 738.05 215.75 755.87 204.3C714.93 205.53 659.57 195.12 579 163.33Z" fill="url(#paint8_linear_1501_16722)"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1501_16732" x1="433.489" y1="200.923" x2="716.471" y2="237.75" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#AFD803"/>
|
||||
<stop offset="1" stop-color="#6CBF00"/>
|
||||
<linearGradient id="paint0_linear_1501_16722" x1="46.5001" y1="344.5" x2="978.5" y2="903" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#E54033"/>
|
||||
<stop offset="0.489583" stop-color="#FECA1A"/>
|
||||
<stop offset="1" stop-color="#AFD803"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_1501_16732" x1="424.179" y1="82.488" x2="788.603" y2="216.813" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint1_linear_1501_16722" x1="263767" y1="31225.5" x2="205421" y2="-28791.6" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.15" stop-color="#6CBF00"/>
|
||||
<stop offset="1" stop-color="#AFD803"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_1501_16732" x1="207.351" y1="837.218" x2="789.9" y2="695.572" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint2_linear_1501_16722" x1="207.43" y1="837.73" x2="791.43" y2="695.73" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.21" stop-color="#E54033"/>
|
||||
<stop offset="0.84" stop-color="#FECA1A"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint3_linear_1501_16732" x1="666.315" y1="797.926" x2="846.068" y2="799.273" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint3_linear_1501_16722" x1="667.54" y1="798.34" x2="847.74" y2="799.69" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FECA1A"/>
|
||||
<stop offset="0.4" stop-color="#FECA1A"/>
|
||||
<stop offset="1" stop-color="#AFD803"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint4_linear_1501_16732" x1="259.44" y1="840.849" x2="627.971" y2="341.923" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint4_linear_1501_16722" x1="259.65" y1="841.37" x2="629.1" y2="341.2" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.16" stop-color="#E54033"/>
|
||||
<stop offset="0.84" stop-color="#FECA1A"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint5_linear_1501_16732" x1="205.774" y1="345.103" x2="189.455" y2="667.361" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint5_linear_1501_16722" x1="205.85" y1="344.39" x2="189.49" y2="667.45" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FECA1A"/>
|
||||
<stop offset="0.76" stop-color="#E54033"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint6_linear_1501_16732" x1="386.054" y1="261.422" x2="287.63" y2="635.161" gradientUnits="userSpaceOnUse">
|
||||
<linearGradient id="paint6_linear_1501_16722" x1="386.58" y1="260.5" x2="287.91" y2="635.17" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.16" stop-color="#FECA1A"/>
|
||||
<stop offset="1" stop-color="#E54033"/>
|
||||
</linearGradient>
|
||||
<clipPath id="clip0_1501_16732">
|
||||
<rect width="715.21" height="860.578" fill="white" transform="translate(135 73)"/>
|
||||
</clipPath>
|
||||
<linearGradient id="paint7_linear_1501_16722" x1="424.8" y1="81.1199" x2="790.13" y2="215.78" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.15" stop-color="#6CBF00"/>
|
||||
<stop offset="1" stop-color="#AFD803"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint8_linear_1501_16722" x1="434.133" y1="199.85" x2="717.819" y2="236.768" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#AFD803"/>
|
||||
<stop offset="1" stop-color="#6CBF00"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 6.1 KiB |
|
@ -21,7 +21,7 @@ import {
|
|||
} from '@blockworks-foundation/mango-v4'
|
||||
|
||||
import EmptyWallet from '../utils/wallet'
|
||||
import { Notification, notify } from '../utils/notifications'
|
||||
import { TransactionNotification, notify } from '../utils/notifications'
|
||||
import {
|
||||
getNFTsByOwner,
|
||||
getTokenAccountsByOwnerWithWrappedSol,
|
||||
|
@ -159,8 +159,8 @@ export type MangoStore = {
|
|||
}
|
||||
mangoAccounts: MangoAccount[]
|
||||
markets: Serum3Market[] | undefined
|
||||
notificationIdCounter: number
|
||||
notifications: Array<Notification>
|
||||
transactionNotificationIdCounter: number
|
||||
transactionNotifications: Array<TransactionNotification>
|
||||
perpMarkets: PerpMarket[]
|
||||
perpStats: {
|
||||
loading: boolean
|
||||
|
@ -305,8 +305,8 @@ const mangoStore = create<MangoStore>()(
|
|||
},
|
||||
mangoAccounts: [],
|
||||
markets: undefined,
|
||||
notificationIdCounter: 0,
|
||||
notifications: [],
|
||||
transactionNotificationIdCounter: 0,
|
||||
transactionNotifications: [],
|
||||
perpMarkets: [],
|
||||
perpStats: {
|
||||
loading: false,
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import produce from 'immer'
|
||||
import Cookies from 'js-cookie'
|
||||
import create from 'zustand'
|
||||
|
||||
type ICookieStore = {
|
||||
currentToken: string
|
||||
set: (x: (x: ICookieStore) => void) => void
|
||||
updateCookie: (wallet?: string) => void
|
||||
removeCookie: (wallet: string) => void
|
||||
setCookie: (wallet: string, token: string) => void
|
||||
}
|
||||
|
||||
const CookieStore = create<ICookieStore>((set, get) => ({
|
||||
currentToken: '',
|
||||
set: (fn) => set(produce(fn)),
|
||||
updateCookie: async (wallet?: string) => {
|
||||
const set = get().set
|
||||
const token = wallet ? getWalletToken(wallet) : ''
|
||||
set((state) => {
|
||||
state.currentToken = token
|
||||
})
|
||||
},
|
||||
removeCookie: async (wallet: string) => {
|
||||
const set = get().set
|
||||
if (getWalletToken(wallet)) {
|
||||
removeWalletToken(wallet)
|
||||
set((state) => {
|
||||
state.currentToken = ''
|
||||
})
|
||||
}
|
||||
},
|
||||
setCookie: async (wallet: string, token: string) => {
|
||||
const set = get().set
|
||||
setWalletToken(wallet, token)
|
||||
set((state) => {
|
||||
state.currentToken = token
|
||||
})
|
||||
},
|
||||
}))
|
||||
|
||||
export default CookieStore
|
||||
|
||||
const cookieName = 'authToken-'
|
||||
|
||||
const getWalletToken = (wallet: string) => {
|
||||
const token = Cookies.get(`${cookieName}${wallet}`)
|
||||
return token || ''
|
||||
}
|
||||
|
||||
const removeWalletToken = (wallet: string) => {
|
||||
Cookies.remove(`${cookieName}${wallet}`)
|
||||
}
|
||||
|
||||
const setWalletToken = (wallet: string, token: string) => {
|
||||
Cookies.set(`${cookieName}${wallet}`, token, {
|
||||
secure: true,
|
||||
sameSite: 'strict',
|
||||
expires: 360,
|
||||
})
|
||||
}
|
|
@ -416,7 +416,8 @@ svg {
|
|||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
h3,
|
||||
h4 {
|
||||
@apply font-bold text-th-fgd-1;
|
||||
}
|
||||
|
||||
|
|
|
@ -288,6 +288,7 @@ export interface NFT {
|
|||
export interface PerpStatsItem {
|
||||
date_hour: string
|
||||
fees_accrued: number
|
||||
fees_settled: number
|
||||
funding_rate_hourly: number
|
||||
instantaneous_funding_rate: number
|
||||
mango_group: string
|
||||
|
@ -296,6 +297,7 @@ export interface PerpStatsItem {
|
|||
perp_market: string
|
||||
price: number
|
||||
stable_price: number
|
||||
total_fees: number
|
||||
}
|
||||
|
||||
export type ActivityFeed = {
|
||||
|
|
|
@ -87,4 +87,7 @@ export const TRADE_VOLUME_ALERT_KEY = 'tradeVolumeAlert-0.1'
|
|||
export const PAGINATION_PAGE_LENGTH = 250
|
||||
|
||||
export const JUPITER_API_MAINNET = 'https://token.jup.ag/strict'
|
||||
|
||||
export const JUPITER_API_DEVNET = 'https://api.jup.ag/api/tokens/devnet'
|
||||
|
||||
export const NOTIFICATION_API = 'https://notifications-api.herokuapp.com/'
|
||||
|
|
|
@ -3,7 +3,7 @@ import mangoStore from '@store/mangoStore'
|
|||
import { Howl } from 'howler'
|
||||
import { SOUND_SETTINGS_KEY } from './constants'
|
||||
|
||||
export type Notification = {
|
||||
export type TransactionNotification = {
|
||||
type: 'success' | 'info' | 'error' | 'confirm'
|
||||
title: string
|
||||
description?: null | string
|
||||
|
@ -29,8 +29,8 @@ export function notify(newNotification: {
|
|||
noSound?: boolean
|
||||
}) {
|
||||
const setMangoStore = mangoStore.getState().set
|
||||
const notifications = mangoStore.getState().notifications
|
||||
const lastId = mangoStore.getState().notificationIdCounter
|
||||
const notifications = mangoStore.getState().transactionNotifications
|
||||
const lastId = mangoStore.getState().transactionNotificationIdCounter
|
||||
const newId = lastId + 1
|
||||
const savedSoundSettings = localStorage.getItem(SOUND_SETTINGS_KEY)
|
||||
const soundSettings = savedSoundSettings
|
||||
|
@ -53,7 +53,7 @@ export function notify(newNotification: {
|
|||
}
|
||||
}
|
||||
|
||||
const newNotif: Notification = {
|
||||
const newNotif: TransactionNotification = {
|
||||
id: newId,
|
||||
type: 'success',
|
||||
show: true,
|
||||
|
@ -62,7 +62,7 @@ export function notify(newNotification: {
|
|||
}
|
||||
|
||||
setMangoStore((state) => {
|
||||
state.notificationIdCounter = newId
|
||||
state.notifications = [...notifications, newNotif]
|
||||
state.transactionNotificationIdCounter = newId
|
||||
state.transactionNotifications = [...notifications, newNotif]
|
||||
})
|
||||
}
|
||||
|
|
30
yarn.lock
30
yarn.lock
|
@ -2157,6 +2157,11 @@
|
|||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/js-cookie@3.0.3":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.3.tgz#d6bfbbdd0c187354ca555213d1962f6d0691ff4e"
|
||||
integrity sha512-Xe7IImK09HP1sv2M/aI+48a20VX+TdRJucfq4vfRVy6nWN8PYPOEnlMRSgxJAgYQIXJVL8dZ4/ilAM7dWNaOww==
|
||||
|
||||
"@types/json-schema@^7.0.9":
|
||||
version "7.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
|
||||
|
@ -2669,6 +2674,16 @@
|
|||
"@walletconnect/window-getters" "^1.0.1"
|
||||
tslib "1.14.1"
|
||||
|
||||
"@web3auth/sign-in-with-solana@1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@web3auth/sign-in-with-solana/-/sign-in-with-solana-1.0.0.tgz#f7fedff74bc47782fb84fc176dc942095e81eb1f"
|
||||
integrity sha512-YwgROXLDfmaqk9lh6hLO/VSKR32FxftOd01aLUMic4yM1IQ00/hx0/12phzE5gn3uiuBZVoHv6yWEAFmnfxh2Q==
|
||||
dependencies:
|
||||
"@stablelib/random" "^1.0.1"
|
||||
bs58 "^5.0.0"
|
||||
tweetnacl "^1.0.3"
|
||||
valid-url "^1.0.9"
|
||||
|
||||
JSONStream@^1.3.5:
|
||||
version "1.3.5"
|
||||
resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0"
|
||||
|
@ -5754,6 +5769,11 @@ js-base64@^3.7.2:
|
|||
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-3.7.5.tgz#21e24cf6b886f76d6f5f165bfcd69cc55b9e3fca"
|
||||
integrity sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==
|
||||
|
||||
js-cookie@3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.1.tgz#9e39b4c6c2f56563708d7d31f6f5f21873a92414"
|
||||
integrity sha512-+0rgsUXZu4ncpPxRL+lNEptWMOWl9etvPHc/koSRp6MPwpRYAhmk0dUG00J4bxVV3r9uUzfo24wW0knS07SKSw==
|
||||
|
||||
js-sha256@^0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966"
|
||||
|
@ -8340,6 +8360,11 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
|||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==
|
||||
|
||||
tweetnacl@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596"
|
||||
integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==
|
||||
|
||||
type-check@^0.4.0, type-check@~0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
|
||||
|
@ -8483,6 +8508,11 @@ v8-compile-cache@^2.0.3:
|
|||
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
|
||||
integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==
|
||||
|
||||
valid-url@^1.0.9:
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200"
|
||||
integrity sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==
|
||||
|
||||
verror@1.10.0:
|
||||
version "1.10.0"
|
||||
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
|
||||
|
|
Loading…
Reference in New Issue