Add wallet limit banner (#699)
* Colorize balance if over soft limit * Remove default banner export --------- Co-authored-by: ekzyis <ek@stacker.news>
This commit is contained in:
parent
c6c75f594e
commit
01984c0b43
@ -5,8 +5,10 @@ import { useMe } from '../components/me'
|
|||||||
import { useMutation } from '@apollo/client'
|
import { useMutation } from '@apollo/client'
|
||||||
import { WELCOME_BANNER_MUTATION } from '../fragments/users'
|
import { WELCOME_BANNER_MUTATION } from '../fragments/users'
|
||||||
import { useToast } from '../components/toast'
|
import { useToast } from '../components/toast'
|
||||||
|
import { BALANCE_LIMIT_MSATS } from '../lib/constants'
|
||||||
|
import { msatsToSats, numWithUnits } from '../lib/format'
|
||||||
|
|
||||||
export default function WelcomeBanner () {
|
export function WelcomeBanner () {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const toaster = useToast()
|
const toaster = useToast()
|
||||||
const [hidden, setHidden] = useState(true)
|
const [hidden, setHidden] = useState(true)
|
||||||
@ -65,3 +67,20 @@ export default function WelcomeBanner () {
|
|||||||
</Alert>
|
</Alert>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function WalletLimitBanner () {
|
||||||
|
const me = useMe()
|
||||||
|
|
||||||
|
const limitReached = me?.privates?.sats >= msatsToSats(BALANCE_LIMIT_MSATS)
|
||||||
|
if (!me || !limitReached) return
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert className={styles.banner} key='info' variant='warning'>
|
||||||
|
<p>
|
||||||
|
Your wallet is over the current limit ({numWithUnits(msatsToSats(BALANCE_LIMIT_MSATS))}).<br />
|
||||||
|
You will not be able to deposit any more funds or receive sats from outside of SN.<br />
|
||||||
|
Please withdraw sats to restore full wallet functionality.
|
||||||
|
</p>
|
||||||
|
</Alert>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -12,13 +12,13 @@ import Head from 'next/head'
|
|||||||
import { signOut } from 'next-auth/react'
|
import { signOut } from 'next-auth/react'
|
||||||
import { useCallback, useEffect } from 'react'
|
import { useCallback, useEffect } from 'react'
|
||||||
import { randInRange } from '../lib/rand'
|
import { randInRange } from '../lib/rand'
|
||||||
import { abbrNum } from '../lib/format'
|
import { abbrNum, msatsToSats } from '../lib/format'
|
||||||
import NoteIcon from '../svgs/notification-4-fill.svg'
|
import NoteIcon from '../svgs/notification-4-fill.svg'
|
||||||
import { useQuery } from '@apollo/client'
|
import { useQuery } from '@apollo/client'
|
||||||
import LightningIcon from '../svgs/bolt.svg'
|
import LightningIcon from '../svgs/bolt.svg'
|
||||||
import SearchIcon from '../svgs/search-line.svg'
|
import SearchIcon from '../svgs/search-line.svg'
|
||||||
import BackArrow from '../svgs/arrow-left-line.svg'
|
import BackArrow from '../svgs/arrow-left-line.svg'
|
||||||
import { SSR } from '../lib/constants'
|
import { BALANCE_LIMIT_MSATS, SSR } from '../lib/constants'
|
||||||
import { useLightning } from './lightning'
|
import { useLightning } from './lightning'
|
||||||
import { HAS_NOTIFICATIONS } from '../fragments/notifications'
|
import { HAS_NOTIFICATIONS } from '../fragments/notifications'
|
||||||
import AnonIcon from '../svgs/spy-fill.svg'
|
import AnonIcon from '../svgs/spy-fill.svg'
|
||||||
@ -153,13 +153,15 @@ function NavProfileMenu ({ me, dropNavKey }) {
|
|||||||
function StackerCorner ({ dropNavKey }) {
|
function StackerCorner ({ dropNavKey }) {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
|
|
||||||
|
const walletLimitReached = me.privates?.sats >= msatsToSats(BALANCE_LIMIT_MSATS)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='d-flex ms-auto'>
|
<div className='d-flex ms-auto'>
|
||||||
<NotificationBell />
|
<NotificationBell />
|
||||||
<NavProfileMenu me={me} dropNavKey={dropNavKey} />
|
<NavProfileMenu me={me} dropNavKey={dropNavKey} />
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Link href='/wallet' passHref legacyBehavior>
|
<Link href='/wallet' passHref legacyBehavior>
|
||||||
<Nav.Link eventKey='wallet' className='text-success text-monospace px-0 text-nowrap'>
|
<Nav.Link eventKey='wallet' className={`${walletLimitReached ? 'text-warning' : 'text-success'} text-monospace px-0 text-nowrap`}>
|
||||||
<WalletSummary me={me} />
|
<WalletSummary me={me} />
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -15,8 +15,8 @@ import { CREATE_WITHDRAWL, SEND_TO_LNADDR } from '../fragments/wallet'
|
|||||||
import { getGetServerSideProps } from '../api/ssrApollo'
|
import { getGetServerSideProps } from '../api/ssrApollo'
|
||||||
import { amountSchema, lnAddrSchema, withdrawlSchema } from '../lib/validate'
|
import { amountSchema, lnAddrSchema, withdrawlSchema } from '../lib/validate'
|
||||||
import Nav from 'react-bootstrap/Nav'
|
import Nav from 'react-bootstrap/Nav'
|
||||||
import { SSR } from '../lib/constants'
|
import { BALANCE_LIMIT_MSATS, SSR } from '../lib/constants'
|
||||||
import { numWithUnits } from '../lib/format'
|
import { msatsToSats, numWithUnits } from '../lib/format'
|
||||||
import styles from '../components/user-header.module.css'
|
import styles from '../components/user-header.module.css'
|
||||||
import HiddenWalletSummary from '../components/hidden-wallet-summary'
|
import HiddenWalletSummary from '../components/hidden-wallet-summary'
|
||||||
import AccordianItem from '../components/accordian-item'
|
import AccordianItem from '../components/accordian-item'
|
||||||
@ -27,6 +27,7 @@ import CameraIcon from '../svgs/camera-line.svg'
|
|||||||
import { useShowModal } from '../components/modal'
|
import { useShowModal } from '../components/modal'
|
||||||
import { useField } from 'formik'
|
import { useField } from 'formik'
|
||||||
import { useToast } from '../components/toast'
|
import { useToast } from '../components/toast'
|
||||||
|
import { WalletLimitBanner } from '../components/banners'
|
||||||
|
|
||||||
export const getServerSideProps = getGetServerSideProps({ authRequired: true })
|
export const getServerSideProps = getGetServerSideProps({ authRequired: true })
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ export default function Wallet () {
|
|||||||
return (
|
return (
|
||||||
<CenterLayout>
|
<CenterLayout>
|
||||||
<YouHaveSats />
|
<YouHaveSats />
|
||||||
|
<WalletLimitBanner />
|
||||||
<WalletForm />
|
<WalletForm />
|
||||||
<WalletHistory />
|
<WalletHistory />
|
||||||
</CenterLayout>
|
</CenterLayout>
|
||||||
@ -58,8 +60,9 @@ export default function Wallet () {
|
|||||||
|
|
||||||
function YouHaveSats () {
|
function YouHaveSats () {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
|
const limitReached = me?.privates?.sats >= msatsToSats(BALANCE_LIMIT_MSATS)
|
||||||
return (
|
return (
|
||||||
<h2 className={`${me ? 'visible' : 'invisible'} text-success`}>
|
<h2 className={`${me ? 'visible' : 'invisible'} ${limitReached ? 'text-warning' : 'text-success'}`}>
|
||||||
you have{' '}
|
you have{' '}
|
||||||
<span className='text-monospace'>{me && (
|
<span className='text-monospace'>{me && (
|
||||||
me.privates?.hideWalletBalance
|
me.privates?.hideWalletBalance
|
||||||
@ -115,6 +118,7 @@ export function FundForm () {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<YouHaveSats />
|
<YouHaveSats />
|
||||||
|
<WalletLimitBanner />
|
||||||
<div className='w-100 py-5'>
|
<div className='w-100 py-5'>
|
||||||
{me && showAlert &&
|
{me && showAlert &&
|
||||||
<Alert
|
<Alert
|
||||||
|
@ -4,7 +4,7 @@ import Items from '../../components/items'
|
|||||||
import Layout from '../../components/layout'
|
import Layout from '../../components/layout'
|
||||||
import { SUB_FULL, SUB_ITEMS } from '../../fragments/subs'
|
import { SUB_FULL, SUB_ITEMS } from '../../fragments/subs'
|
||||||
import Snl from '../../components/snl'
|
import Snl from '../../components/snl'
|
||||||
import WelcomeBanner from '../../components/banners'
|
import { WelcomeBanner } from '../../components/banners'
|
||||||
import { AccordianCard } from '../../components/accordian-item'
|
import { AccordianCard } from '../../components/accordian-item'
|
||||||
import Text from '../../components/text'
|
import Text from '../../components/text'
|
||||||
import { useMe } from '../../components/me'
|
import { useMe } from '../../components/me'
|
||||||
|
@ -464,12 +464,12 @@ div[contenteditable]:disabled,
|
|||||||
border-color: var(--theme-borderColor);
|
border-color: var(--theme-borderColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-link:not(.text-success) {
|
.nav-link:not(.text-success, .text-warning) {
|
||||||
color: var(--theme-navLink) !important;
|
color: var(--theme-navLink) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-link:not(.text-success):hover,
|
.nav-link:not(.text-success, .text-warning):hover,
|
||||||
.nav-link:not(.text-success):focus {
|
.nav-link:not(.text-success, .text-warning):focus {
|
||||||
color: var(--theme-navLinkFocus) !important;
|
color: var(--theme-navLinkFocus) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,7 +691,7 @@ div[contenteditable]:focus,
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-link.active:not(.text-success) {
|
.nav-link.active:not(.text-success, .text-warning) {
|
||||||
color: var(--theme-navLinkActive) !important;
|
color: var(--theme-navLinkActive) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user