import { getGetServerSideProps } from '@/api/ssrApollo' import { CenterLayout } from '@/components/layout' import Link from 'next/link' import { useRouter } from 'next/router' import { InputGroup, Nav } from 'react-bootstrap' import styles from '@/components/user-header.module.css' import { gql, useMutation, useQuery } from '@apollo/client' import { CREATE_WITHDRAWL, SEND_TO_LNADDR } from '@/fragments/wallet' import { requestProvider } from 'webln' import { useEffect, useState } from 'react' import { useMe } from '@/components/me' import { WithdrawlSkeleton } from './withdrawals/[id]' import { Checkbox, Form, Input, InputUserSuggest, SubmitButton } from '@/components/form' import { lnAddrSchema, withdrawlSchema } from '@/lib/validate' import { useShowModal } from '@/components/modal' import { useField } from 'formik' import { useToast } from '@/components/toast' import { Scanner } from '@yudiel/react-qr-scanner' import { decode } from 'bolt11' import CameraIcon from '@/svgs/camera-line.svg' import { FAST_POLL_INTERVAL, SSR } from '@/lib/constants' import Qr, { QrSkeleton } from '@/components/qr' import useDebounceCallback from '@/components/use-debounce-callback' import { lnAddrOptions } from '@/lib/lnurl' import AccordianItem from '@/components/accordian-item' import { numWithUnits } from '@/lib/format' export const getServerSideProps = getGetServerSideProps({ authRequired: true }) export default function Withdraw () { return ( ) } function WithdrawForm () { const router = useRouter() const { me } = useMe() return (

{numWithUnits(me?.privates?.sats - me?.privates?.credits, { abbreviate: false, format: true, unitSingular: 'sats', unitPlural: 'sats' })}

) } export function SelectedWithdrawalForm () { const router = useRouter() switch (router.query.type) { case 'lnurl': return case 'lnaddr': return default: return } } export function InvWithdrawal () { const router = useRouter() const { me } = useMe() const [createWithdrawl, { called, error }] = useMutation(CREATE_WITHDRAWL) const maxFeeDefault = me?.privates?.withdrawMaxFeeDefault useEffect(() => { async function effect () { try { const provider = await requestProvider() const { paymentRequest: invoice } = await provider.makeInvoice({ defaultMemo: `Withdrawal for @${me.name} on SN`, maximumAmount: Math.max(me.privates?.sats - maxFeeDefault, 0) }) const { data } = await createWithdrawl({ variables: { invoice, maxFee: maxFeeDefault } }) router.push(`/withdrawals/${data.createWithdrawl.id}`) } catch (e) { console.log(e.message) } } effect() }, []) if (called && !error) { return } return ( <>
{ const { data } = await createWithdrawl({ variables: { invoice, maxFee: Number(maxFee) } }) router.push(`/withdrawals/${data.createWithdrawl.id}`) }} > } /> sats} />
withdraw
) } function InvoiceScanner ({ fieldName }) { const showModal = useShowModal() const [,, helpers] = useField(fieldName) const toaster = useToast() return ( { showModal(onClose => { return ( { result = result.toLowerCase() if (result.split('lightning=')[1]) { helpers.setValue(result.split('lightning=')[1].split(/[&?]/)[0]) } else if (decode(result.replace(/^lightning:/, ''))) { helpers.setValue(result.replace(/^lightning:/, '')) } else { throw new Error('Not a proper lightning payment request') } onClose() }} styles={{ video: { aspectRatio: '1 / 1' } }} onError={(error) => { if (error instanceof DOMException) { console.log(error) } else { toaster.danger('qr scan: ' + error?.message || error?.toString?.()) } onClose() }} /> ) }) }} > ) } function LnQRWith ({ k1, encodedUrl }) { const router = useRouter() const query = gql` { lnWith(k1: "${k1}") { withdrawalId k1 } }` const { data } = useQuery(query, SSR ? {} : { pollInterval: FAST_POLL_INTERVAL, nextFetchPolicy: 'cache-and-network' }) if (data?.lnWith?.withdrawalId) { router.push(`/withdrawals/${data.lnWith.withdrawalId}`) } return } export function LnurlWithdrawal () { // query for challenge const [createWith, { data, error }] = useMutation(gql` mutation createWith { createWith { k1 encodedUrl } }`) const toaster = useToast() useEffect(() => { createWith().catch(e => { toaster.danger('withdrawal creation: ' + e?.message || e?.toString?.()) }) }, [createWith, toaster]) if (error) return if (!data) { return } return } export function LnAddrWithdrawal () { const { me } = useMe() const router = useRouter() const [sendToLnAddr, { called, error }] = useMutation(SEND_TO_LNADDR) const defaultOptions = { min: 1 } const [addrOptions, setAddrOptions] = useState(defaultOptions) const [formSchema, setFormSchema] = useState(lnAddrSchema()) const maxFeeDefault = me?.privates?.withdrawMaxFeeDefault const onAddrChange = useDebounceCallback(async (formik, e) => { if (!e?.target?.value) { setAddrOptions(defaultOptions) setFormSchema(lnAddrSchema()) return } let options try { options = await lnAddrOptions(e.target.value) setAddrOptions(options) setFormSchema(lnAddrSchema(options)) } catch (e) { console.log(e) setAddrOptions(defaultOptions) setFormSchema(lnAddrSchema()) } }, 500, [setAddrOptions, setFormSchema]) return ( <> {called && !error && }
{ const { data } = await sendToLnAddr({ variables: { amount: Number(amount), maxFee: Number(maxFee), ...values } }) router.push(`/withdrawals/${data.sendToLnAddr.id}`) }} > ({ ...user, name: `${user.name}@stacker.news` })} selectWithTab filterUsers={(query) => { const [, domain] = query.split('@') return !domain || 'stacker.news'.startsWith(domain) }} /> sats} /> sats} /> {(addrOptions?.commentAllowed || addrOptions?.payerData) &&
attach
} body={ <> {addrOptions.commentAllowed && comment optional} name='comment' maxLength={addrOptions.commentAllowed} />} {addrOptions.payerData?.identifier && your {me?.name}@stacker.news identifier {!addrOptions.payerData.identifier.mandatory && <>{' '}optional} } />} {addrOptions.payerData?.name && name{!addrOptions.payerData.name.mandatory && <>{' '}optional} } />} {addrOptions.payerData?.email && email{!addrOptions.payerData.email.mandatory && <>{' '}optional} } />} } />
}
send
) }