Allow pay per invoice for stackers
The modal which pops up if the stacker does not have enough sats now has two options: "fund wallet" and "pay invoice"
This commit is contained in:
parent
fd8510d59f
commit
853a389b65
@ -14,7 +14,6 @@ import { SubSelectInitial } from './sub-select-form'
|
|||||||
import CancelButton from './cancel-button'
|
import CancelButton from './cancel-button'
|
||||||
import { useCallback } from 'react'
|
import { useCallback } from 'react'
|
||||||
import { useAnonymous } from '../lib/anonymous'
|
import { useAnonymous } from '../lib/anonymous'
|
||||||
import { ANON_POST_FEE } from '../lib/constants'
|
|
||||||
|
|
||||||
export function DiscussionForm ({
|
export function DiscussionForm ({
|
||||||
item, sub, editThreshold, titleLabel = 'title',
|
item, sub, editThreshold, titleLabel = 'title',
|
||||||
@ -79,8 +78,8 @@ export function DiscussionForm ({
|
|||||||
...SubSelectInitial({ sub: item?.subName || sub?.name })
|
...SubSelectInitial({ sub: item?.subName || sub?.name })
|
||||||
}}
|
}}
|
||||||
schema={schema}
|
schema={schema}
|
||||||
onSubmit={handleSubmit || (async ({ boost, ...values }) => {
|
onSubmit={handleSubmit || (async ({ boost, cost, ...values }) => {
|
||||||
await anonUpsertDiscussion(ANON_POST_FEE, boost, values)
|
await anonUpsertDiscussion(cost, boost, values)
|
||||||
})}
|
})}
|
||||||
storageKeyPrefix={item ? undefined : 'discussion'}
|
storageKeyPrefix={item ? undefined : 'discussion'}
|
||||||
>
|
>
|
||||||
|
@ -6,6 +6,7 @@ import { gql, useQuery } from '@apollo/client'
|
|||||||
import { useFormikContext } from 'formik'
|
import { useFormikContext } from 'formik'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
import { ANON_COMMENT_FEE, ANON_POST_FEE } from '../lib/constants'
|
import { ANON_COMMENT_FEE, ANON_POST_FEE } from '../lib/constants'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
|
||||||
function Receipt ({ cost, repetition, hasImgLink, baseFee, parentId, boost }) {
|
function Receipt ({ cost, repetition, hasImgLink, baseFee, parentId, boost }) {
|
||||||
return (
|
return (
|
||||||
@ -53,6 +54,10 @@ export default function FeeButton ({ parentId, hasImgLink, baseFee, ChildButton,
|
|||||||
const boost = Number(formik?.values?.boost) || 0
|
const boost = Number(formik?.values?.boost) || 0
|
||||||
const cost = baseFee * (hasImgLink ? 10 : 1) * Math.pow(10, repetition) + Number(boost)
|
const cost = baseFee * (hasImgLink ? 10 : 1) * Math.pow(10, repetition) + Number(boost)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
formik.setFieldValue('cost', cost)
|
||||||
|
}, [cost])
|
||||||
|
|
||||||
const show = alwaysShow || !formik?.isSubmitting
|
const show = alwaysShow || !formik?.isSubmitting
|
||||||
return (
|
return (
|
||||||
<div className='d-flex align-items-center'>
|
<div className='d-flex align-items-center'>
|
||||||
|
@ -1,14 +1,18 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import Button from 'react-bootstrap/Button'
|
import Button from 'react-bootstrap/Button'
|
||||||
|
import { useAnonymous } from '../lib/anonymous'
|
||||||
|
|
||||||
export default function FundError ({ onClose }) {
|
export default function FundError ({ onClose, amount, onPayment }) {
|
||||||
|
const anonPayment = useAnonymous(onPayment, { forceInvoice: true })
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<p className='fw-bolder'>you need more sats</p>
|
<p className='fw-bolder'>you need more sats</p>
|
||||||
<div className='d-flex justify-content-end'>
|
<div className='d-flex justify-content-end'>
|
||||||
<Link href='/wallet?type=fund'>
|
<Link href='/wallet?type=fund'>
|
||||||
<Button variant='success' onClick={onClose}>fund</Button>
|
<Button variant='success' onClick={onClose}>fund wallet</Button>
|
||||||
</Link>
|
</Link>
|
||||||
|
<span className='d-flex mx-3 font-weight-bold text-muted align-items-center'>or</span>
|
||||||
|
<Button variant='success' onClick={() => anonPayment(amount)}>pay invoice</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -6,6 +6,8 @@ import { useMe } from './me'
|
|||||||
import UpBolt from '../svgs/bolt.svg'
|
import UpBolt from '../svgs/bolt.svg'
|
||||||
import { amountSchema } from '../lib/validate'
|
import { amountSchema } from '../lib/validate'
|
||||||
import { useAnonymous } from '../lib/anonymous'
|
import { useAnonymous } from '../lib/anonymous'
|
||||||
|
import { useShowModal } from './modal'
|
||||||
|
import FundError from './fund-error'
|
||||||
|
|
||||||
const defaultTips = [100, 1000, 10000, 100000]
|
const defaultTips = [100, 1000, 10000, 100000]
|
||||||
|
|
||||||
@ -41,6 +43,7 @@ export default function ItemAct ({ onClose, itemId, act, strike }) {
|
|||||||
const inputRef = useRef(null)
|
const inputRef = useRef(null)
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const [oValue, setOValue] = useState()
|
const [oValue, setOValue] = useState()
|
||||||
|
const showModal = useShowModal()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
inputRef.current?.focus()
|
inputRef.current?.focus()
|
||||||
@ -75,7 +78,23 @@ export default function ItemAct ({ onClose, itemId, act, strike }) {
|
|||||||
}}
|
}}
|
||||||
schema={amountSchema}
|
schema={amountSchema}
|
||||||
onSubmit={async ({ amount }) => {
|
onSubmit={async ({ amount }) => {
|
||||||
await anonAct(amount)
|
try {
|
||||||
|
await anonAct(amount)
|
||||||
|
} catch (error) {
|
||||||
|
if (error.toString().includes('insufficient funds')) {
|
||||||
|
showModal(onClose => {
|
||||||
|
return (
|
||||||
|
<FundError
|
||||||
|
onClose={onClose}
|
||||||
|
amount={amount}
|
||||||
|
onPayment={submitAct}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
throw new Error({ message: error.toString() })
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
|
@ -15,7 +15,6 @@ import Moon from '../svgs/moon-fill.svg'
|
|||||||
import { SubSelectInitial } from './sub-select-form'
|
import { SubSelectInitial } from './sub-select-form'
|
||||||
import CancelButton from './cancel-button'
|
import CancelButton from './cancel-button'
|
||||||
import { useAnonymous } from '../lib/anonymous'
|
import { useAnonymous } from '../lib/anonymous'
|
||||||
import { ANON_POST_FEE } from '../lib/constants'
|
|
||||||
|
|
||||||
export function LinkForm ({ item, sub, editThreshold, children }) {
|
export function LinkForm ({ item, sub, editThreshold, children }) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -119,8 +118,8 @@ export function LinkForm ({ item, sub, editThreshold, children }) {
|
|||||||
...SubSelectInitial({ sub: item?.subName || sub?.name })
|
...SubSelectInitial({ sub: item?.subName || sub?.name })
|
||||||
}}
|
}}
|
||||||
schema={schema}
|
schema={schema}
|
||||||
onSubmit={async ({ boost, title, ...values }) => {
|
onSubmit={async ({ boost, title, cost, ...values }) => {
|
||||||
await anonUpsertLink(ANON_POST_FEE, boost, title, values)
|
await anonUpsertLink(cost, boost, title, values)
|
||||||
}}
|
}}
|
||||||
storageKeyPrefix={item ? undefined : 'link'}
|
storageKeyPrefix={item ? undefined : 'link'}
|
||||||
>
|
>
|
||||||
|
@ -3,7 +3,7 @@ import { useRouter } from 'next/router'
|
|||||||
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
import { gql, useApolloClient, useMutation } from '@apollo/client'
|
||||||
import Countdown from './countdown'
|
import Countdown from './countdown'
|
||||||
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
import AdvPostForm, { AdvPostInitial } from './adv-post-form'
|
||||||
import { ANON_POST_FEE, MAX_POLL_NUM_CHOICES } from '../lib/constants'
|
import { MAX_POLL_NUM_CHOICES } from '../lib/constants'
|
||||||
import FeeButton, { EditFeeButton } from './fee-button'
|
import FeeButton, { EditFeeButton } from './fee-button'
|
||||||
import Delete from './delete'
|
import Delete from './delete'
|
||||||
import Button from 'react-bootstrap/Button'
|
import Button from 'react-bootstrap/Button'
|
||||||
@ -68,8 +68,8 @@ export function PollForm ({ item, sub, editThreshold, children }) {
|
|||||||
...SubSelectInitial({ sub: item?.subName || sub?.name })
|
...SubSelectInitial({ sub: item?.subName || sub?.name })
|
||||||
}}
|
}}
|
||||||
schema={schema}
|
schema={schema}
|
||||||
onSubmit={async ({ boost, title, options, ...values }) => {
|
onSubmit={async ({ boost, title, options, cost, ...values }) => {
|
||||||
await anonUpsertPoll(ANON_POST_FEE, boost, title, options, values)
|
await anonUpsertPoll(cost, boost, title, options, values)
|
||||||
}}
|
}}
|
||||||
storageKeyPrefix={item ? undefined : 'poll'}
|
storageKeyPrefix={item ? undefined : 'poll'}
|
||||||
>
|
>
|
||||||
|
@ -163,10 +163,11 @@ export default function UpVote ({ item, className, pendingSats, setPendingSats }
|
|||||||
|
|
||||||
if (pendingSats > 0) {
|
if (pendingSats > 0) {
|
||||||
timerRef.current = setTimeout(async (sats) => {
|
timerRef.current = setTimeout(async (sats) => {
|
||||||
|
const variables = { id: item.id, sats: pendingSats }
|
||||||
try {
|
try {
|
||||||
timerRef.current && setPendingSats(0)
|
timerRef.current && setPendingSats(0)
|
||||||
await act({
|
await act({
|
||||||
variables: { id: item.id, sats },
|
variables,
|
||||||
optimisticResponse: {
|
optimisticResponse: {
|
||||||
act: {
|
act: {
|
||||||
sats
|
sats
|
||||||
@ -178,7 +179,15 @@ export default function UpVote ({ item, className, pendingSats, setPendingSats }
|
|||||||
|
|
||||||
if (error.toString().includes('insufficient funds')) {
|
if (error.toString().includes('insufficient funds')) {
|
||||||
showModal(onClose => {
|
showModal(onClose => {
|
||||||
return <FundError onClose={onClose} />
|
return (
|
||||||
|
<FundError
|
||||||
|
onClose={onClose}
|
||||||
|
amount={pendingSats}
|
||||||
|
onPayment={async (_, invoiceHash) => {
|
||||||
|
await act({ variables: { ...variables, invoiceHash } })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import { Invoice as QrInvoice } from '../components/invoice'
|
|||||||
import { QrSkeleton } from '../components/qr'
|
import { QrSkeleton } from '../components/qr'
|
||||||
import { useMe } from '../components/me'
|
import { useMe } from '../components/me'
|
||||||
import { msatsToSats } from './format'
|
import { msatsToSats } from './format'
|
||||||
|
import FundError from '../components/fund-error'
|
||||||
import { INVOICE } from '../fragments/wallet'
|
import { INVOICE } from '../fragments/wallet'
|
||||||
|
|
||||||
const Invoice = ({ id, ...props }) => {
|
const Invoice = ({ id, ...props }) => {
|
||||||
@ -24,7 +25,10 @@ const Invoice = ({ id, ...props }) => {
|
|||||||
return <QrInvoice invoice={data.invoice} {...props} />
|
return <QrInvoice invoice={data.invoice} {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useAnonymous = (fn) => {
|
const defaultOptions = {
|
||||||
|
forceInvoice: false
|
||||||
|
}
|
||||||
|
export const useAnonymous = (fn, options = defaultOptions) => {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const [createInvoice, { data }] = useMutation(gql`
|
const [createInvoice, { data }] = useMutation(gql`
|
||||||
mutation createInvoice($amount: Int!) {
|
mutation createInvoice($amount: Int!) {
|
||||||
@ -55,8 +59,26 @@ export const useAnonymous = (fn) => {
|
|||||||
}
|
}
|
||||||
}, [invoice?.id])
|
}, [invoice?.id])
|
||||||
|
|
||||||
const anonFn = useCallback((amount, ...args) => {
|
const anonFn = useCallback(async (amount, ...args) => {
|
||||||
if (me) return fn(amount, ...args)
|
if (me && !options.forceInvoice) {
|
||||||
|
try {
|
||||||
|
return await fn(amount, ...args)
|
||||||
|
} catch (error) {
|
||||||
|
if (error.toString().includes('insufficient funds')) {
|
||||||
|
showModal(onClose => {
|
||||||
|
return (
|
||||||
|
<FundError
|
||||||
|
onClose={onClose}
|
||||||
|
amount={amount}
|
||||||
|
onPayment={async (_, invoiceHash) => { await fn(amount, ...args, invoiceHash) }}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
throw new Error({ message: error.toString() })
|
||||||
|
}
|
||||||
|
}
|
||||||
setFnArgs(args)
|
setFnArgs(args)
|
||||||
return createInvoice({ variables: { amount } })
|
return createInvoice({ variables: { amount } })
|
||||||
}, [fn, setFnArgs, createInvoice])
|
}, [fn, setFnArgs, createInvoice])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user