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:
ekzyis 2023-12-22 00:31:16 +01:00 committed by GitHub
parent c6c75f594e
commit 01984c0b43
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 12 deletions

View File

@ -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>
)
}

View File

@ -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>

View File

@ -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

View File

@ -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'

View File

@ -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;
} }