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