Hide wallet balance (#481)

* Hide wallet balance on long press

* Use setting to hide wallet balance

* Fix layout shift on hover

* Fix SSR warning about useLayoutEffect

See https://reactjs.org/link/uselayouteffect-ssr

* Also hide balance in wallet

---------

Co-authored-by: ekzyis <ek@stacker.news>
This commit is contained in:
ekzyis 2023-09-12 19:19:26 +02:00 committed by GitHub
parent 1a6dc879a2
commit 6df654b208
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 65 additions and 10 deletions

View File

@ -25,7 +25,7 @@ export default gql`
noteInvites: Boolean!, noteJobIndicator: Boolean!, noteCowboyHat: Boolean!, hideInvoiceDesc: Boolean!, noteInvites: Boolean!, noteJobIndicator: Boolean!, noteCowboyHat: Boolean!, hideInvoiceDesc: Boolean!,
hideFromTopUsers: Boolean!, hideCowboyHat: Boolean!, clickToLoadImg: Boolean!, hideFromTopUsers: Boolean!, hideCowboyHat: Boolean!, clickToLoadImg: Boolean!,
wildWestMode: Boolean!, greeterMode: Boolean!, nostrPubkey: String, nostrRelays: [String!], hideBookmarks: Boolean!, wildWestMode: Boolean!, greeterMode: Boolean!, nostrPubkey: String, nostrRelays: [String!], hideBookmarks: Boolean!,
noteForwardedSats: Boolean!): User noteForwardedSats: Boolean!, hideWalletBalance: Boolean!): User
setPhoto(photoId: ID!): Int! setPhoto(photoId: ID!): Int!
upsertBio(bio: String!): User! upsertBio(bio: String!): User!
setWalkthrough(tipPopover: Boolean, upvotePopover: Boolean): Boolean setWalkthrough(tipPopover: Boolean, upvotePopover: Boolean): Boolean
@ -85,6 +85,7 @@ export default gql`
hideCowboyHat: Boolean! hideCowboyHat: Boolean!
hideBookmarks: Boolean! hideBookmarks: Boolean!
hideWelcomeBanner: Boolean! hideWelcomeBanner: Boolean!
hideWalletBalance: Boolean!
clickToLoadImg: Boolean! clickToLoadImg: Boolean!
wildWestMode: Boolean! wildWestMode: Boolean!
greeterMode: Boolean! greeterMode: Boolean!

View File

@ -10,7 +10,7 @@ import Price from './price'
import { useMe } from './me' import { useMe } from './me'
import Head from 'next/head' 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, useState } from 'react'
import { randInRange } from '../lib/rand' import { randInRange } from '../lib/rand'
import { abbrNum } from '../lib/format' import { abbrNum } from '../lib/format'
import NoteIcon from '../svgs/notification-4-fill.svg' import NoteIcon from '../svgs/notification-4-fill.svg'
@ -24,9 +24,21 @@ 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'
import Hat from './hat' import Hat from './hat'
import HiddenWalletSummary from './hidden-wallet-summary'
function WalletSummary ({ me }) { function WalletSummary ({ me, hideBalance }) {
if (!me) return null const [show, setShow] = useState(false)
useEffect(() => {
// fix warning about useLayoutEffect usage during SSR
// see https://reactjs.org/link/uselayouteffect-ssr
setShow(true)
}, [])
if (!me || !show) return null
if (me.hideWalletBalance) {
return <HiddenWalletSummary abbreviate fixedWidth />
}
return `${abbrNum(me.sats)}` return `${abbrNum(me.sats)}`
} }
@ -132,7 +144,9 @@ function StackerCorner ({ dropNavKey }) {
<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 px-0 text-nowrap'><WalletSummary me={me} /></Nav.Link> <Nav.Link eventKey='wallet' className='text-success px-0 text-nowrap'>
<WalletSummary me={me} />
</Nav.Link>
</Link> </Link>
</Nav.Item> </Nav.Item>
</div> </div>

View File

@ -0,0 +1,21 @@
import { useState, useRef, useLayoutEffect } from 'react'
import { abbrNum, numWithUnits } from '../lib/format'
import { useMe } from './me'
export default function HiddenWalletSummary ({ abbreviate, fixedWidth }) {
const me = useMe()
const [hover, setHover] = useState(false)
// prevent layout shifts when hovering by fixing width to initial rendered width
const ref = useRef()
const [width, setWidth] = useState(undefined)
useLayoutEffect(() => {
setWidth(ref.current?.offsetWidth)
}, [])
return (
<span ref={ref} style={{ width: fixedWidth ? width : undefined }} className='d-inline-block' align='right' onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}>
{hover ? (abbreviate ? abbrNum(me.sats) : numWithUnits(me.sats, { abbreviate: false })) : '*****'}
</span>
)
}

View File

@ -35,6 +35,7 @@ export const ME = gql`
greeterMode greeterMode
lastCheckedJobs lastCheckedJobs
hideWelcomeBanner hideWelcomeBanner
hideWalletBalance
} }
}` }`
@ -57,6 +58,7 @@ export const SETTINGS_FIELDS = gql`
hideCowboyHat hideCowboyHat
hideBookmarks hideBookmarks
clickToLoadImg clickToLoadImg
hideWalletBalance
nostrPubkey nostrPubkey
nostrRelays nostrRelays
wildWestMode wildWestMode
@ -86,14 +88,14 @@ mutation setSettings($tipDefault: Int!, $turboTipping: Boolean!, $fiatCurrency:
$noteInvites: Boolean!, $noteJobIndicator: Boolean!, $noteCowboyHat: Boolean!, $hideInvoiceDesc: Boolean!, $noteInvites: Boolean!, $noteJobIndicator: Boolean!, $noteCowboyHat: Boolean!, $hideInvoiceDesc: Boolean!,
$hideFromTopUsers: Boolean!, $hideCowboyHat: Boolean!, $clickToLoadImg: Boolean!, $hideFromTopUsers: Boolean!, $hideCowboyHat: Boolean!, $clickToLoadImg: Boolean!,
$wildWestMode: Boolean!, $greeterMode: Boolean!, $nostrPubkey: String, $nostrRelays: [String!], $hideBookmarks: Boolean!, $wildWestMode: Boolean!, $greeterMode: Boolean!, $nostrPubkey: String, $nostrRelays: [String!], $hideBookmarks: Boolean!,
$noteForwardedSats: Boolean!) { $noteForwardedSats: Boolean!, $hideWalletBalance: Boolean!) {
setSettings(tipDefault: $tipDefault, turboTipping: $turboTipping, fiatCurrency: $fiatCurrency, setSettings(tipDefault: $tipDefault, turboTipping: $turboTipping, fiatCurrency: $fiatCurrency,
noteItemSats: $noteItemSats, noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants, noteItemSats: $noteItemSats, noteEarning: $noteEarning, noteAllDescendants: $noteAllDescendants,
noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites, noteMentions: $noteMentions, noteDeposits: $noteDeposits, noteInvites: $noteInvites,
noteJobIndicator: $noteJobIndicator, noteCowboyHat: $noteCowboyHat, hideInvoiceDesc: $hideInvoiceDesc, noteJobIndicator: $noteJobIndicator, noteCowboyHat: $noteCowboyHat, hideInvoiceDesc: $hideInvoiceDesc,
hideFromTopUsers: $hideFromTopUsers, hideCowboyHat: $hideCowboyHat, clickToLoadImg: $clickToLoadImg, hideFromTopUsers: $hideFromTopUsers, hideCowboyHat: $hideCowboyHat, clickToLoadImg: $clickToLoadImg,
wildWestMode: $wildWestMode, greeterMode: $greeterMode, nostrPubkey: $nostrPubkey, nostrRelays: $nostrRelays, hideBookmarks: $hideBookmarks, wildWestMode: $wildWestMode, greeterMode: $greeterMode, nostrPubkey: $nostrPubkey, nostrRelays: $nostrRelays, hideBookmarks: $hideBookmarks,
noteForwardedSats: $noteForwardedSats) { noteForwardedSats: $noteForwardedSats, hideWalletBalance: $hideWalletBalance) {
...SettingsFields ...SettingsFields
} }
} }

View File

@ -223,7 +223,8 @@ export const settingsSchema = object({
string().matches(WS_REGEXP, 'invalid web socket address') string().matches(WS_REGEXP, 'invalid web socket address')
).max(NOSTR_MAX_RELAY_NUM, ).max(NOSTR_MAX_RELAY_NUM,
({ max, value }) => `${Math.abs(max - value.length)} too many`), ({ max, value }) => `${Math.abs(max - value.length)} too many`),
hideBookmarks: boolean() hideBookmarks: boolean(),
hideWalletBalance: boolean()
}) })
const warningMessage = 'If I logout, even accidentally, I will never be able to access my account again' const warningMessage = 'If I logout, even accidentally, I will never be able to access my account again'

View File

@ -76,7 +76,8 @@ export default function Settings ({ ssrData }) {
greeterMode: settings?.greeterMode, greeterMode: settings?.greeterMode,
nostrPubkey: settings?.nostrPubkey ? bech32encode(settings.nostrPubkey) : '', nostrPubkey: settings?.nostrPubkey ? bech32encode(settings.nostrPubkey) : '',
nostrRelays: settings?.nostrRelays?.length ? settings?.nostrRelays : [''], nostrRelays: settings?.nostrRelays?.length ? settings?.nostrRelays : [''],
hideBookmarks: settings?.hideBookmarks hideBookmarks: settings?.hideBookmarks,
hideWalletBalance: settings?.hideWalletBalance
}} }}
schema={settingsSchema} schema={settingsSchema}
onSubmit={async ({ tipDefault, nostrPubkey, nostrRelays, ...values }) => { onSubmit={async ({ tipDefault, nostrPubkey, nostrRelays, ...values }) => {
@ -230,6 +231,11 @@ export default function Settings ({ ssrData }) {
name='hideCowboyHat' name='hideCowboyHat'
groupClassName='mb-0' groupClassName='mb-0'
/> />
<Checkbox
label={<>hide my wallet balance</>}
name='hideWalletBalance'
groupClassName='mb-0'
/>
<Checkbox <Checkbox
label={<>click to load external images</>} label={<>click to load external images</>}
name='clickToLoadImg' name='clickToLoadImg'

View File

@ -18,6 +18,7 @@ import Nav from 'react-bootstrap/Nav'
import { SSR } from '../lib/constants' import { SSR } from '../lib/constants'
import { numWithUnits } from '../lib/format' import { 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'
export const getServerSideProps = getGetServerSideProps({ authRequired: true }) export const getServerSideProps = getGetServerSideProps({ authRequired: true })
@ -51,7 +52,13 @@ function YouHaveSats () {
const me = useMe() const me = useMe()
return ( return (
<h2 className={`${me ? 'visible' : 'invisible'} text-success`}> <h2 className={`${me ? 'visible' : 'invisible'} text-success`}>
you have <span className='text-monospace'>{me && numWithUnits(me.sats, { abbreviate: false })}</span> you have{' '}
<span className='text-monospace'>{me && (
me.hideWalletBalance
? <HiddenWalletSummary />
: numWithUnits(me.sats, { abbreviate: false })
)}
</span>
</h2> </h2>
) )
} }

View File

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "users" ADD COLUMN "hideWalletBalance" BOOLEAN NOT NULL DEFAULT false;

View File

@ -51,6 +51,7 @@ model User {
hideFromTopUsers Boolean @default(false) hideFromTopUsers Boolean @default(false)
turboTipping Boolean @default(false) turboTipping Boolean @default(false)
clickToLoadImg Boolean @default(false) clickToLoadImg Boolean @default(false)
hideWalletBalance Boolean @default(false)
referrerId Int? referrerId Int?
nostrPubkey String? nostrPubkey String?
nostrAuthPubkey String? @unique(map: "users.nostrAuthPubkey_unique") nostrAuthPubkey String? @unique(map: "users.nostrAuthPubkey_unique")