withdrawl page

This commit is contained in:
keyan 2021-05-13 08:28:38 -05:00
parent 7a8afd56c3
commit ce55fdfe9c
6 changed files with 121 additions and 63 deletions

View File

@ -30,6 +30,6 @@ export default gql`
msatsPaid: Int msatsPaid: Int
msatsFeePaying: Int! msatsFeePaying: Int!
msatsFeePaid: Int msatsFeePaid: Int
status: String! status: String
} }
` `

View File

@ -4,6 +4,8 @@ import BootstrapForm from 'react-bootstrap/Form'
import Alert from 'react-bootstrap/Alert' import Alert from 'react-bootstrap/Alert'
import { Formik, Form as FormikForm, useFormikContext, useField } from 'formik' import { Formik, Form as FormikForm, useFormikContext, useField } from 'formik'
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import copy from 'clipboard-copy'
import Thumb from '../svgs/thumb-up-fill.svg'
export function SubmitButton ({ children, variant, ...props }) { export function SubmitButton ({ children, variant, ...props }) {
const { isSubmitting } = useFormikContext() const { isSubmitting } = useFormikContext()
@ -19,8 +21,35 @@ export function SubmitButton ({ children, variant, ...props }) {
) )
} }
export function CopyInput (props) {
const [copied, setCopied] = useState(false)
const handleClick = () => {
copy(props.placeholder)
setCopied(true)
setTimeout(() => setCopied(false), 1500)
}
return (
<Input
onClick={handleClick}
append={<Button onClick={handleClick}>{copied ? <Thumb width={18} height={18} /> : 'copy'}</Button>}
{...props}
/>
)
}
export function InputSkeleton ({ label }) {
return (
<BootstrapForm.Group>
{label && <BootstrapForm.Label>{label}</BootstrapForm.Label>}
<div className='clouds form-control' />
</BootstrapForm.Group>
)
}
export function Input ({ label, prepend, append, hint, ...props }) { export function Input ({ label, prepend, append, hint, ...props }) {
const [field, meta] = useField(props) const [field, meta] = props.readOnly ? [{}, {}] : useField(props)
return ( return (
<BootstrapForm.Group> <BootstrapForm.Group>
@ -28,7 +57,7 @@ export function Input ({ label, prepend, append, hint, ...props }) {
<InputGroup hasValidation> <InputGroup hasValidation>
{prepend && ( {prepend && (
<InputGroup.Prepend> <InputGroup.Prepend>
<InputGroup.Text>{prepend}</InputGroup.Text> {prepend}
</InputGroup.Prepend> </InputGroup.Prepend>
)} )}
<BootstrapForm.Control <BootstrapForm.Control
@ -37,7 +66,7 @@ export function Input ({ label, prepend, append, hint, ...props }) {
/> />
{append && ( {append && (
<InputGroup.Append> <InputGroup.Append>
<InputGroup.Text>{append}</InputGroup.Text> {append}
</InputGroup.Append> </InputGroup.Append>
)} )}
<BootstrapForm.Control.Feedback type='invalid'> <BootstrapForm.Control.Feedback type='invalid'>

View File

@ -0,0 +1,41 @@
import Moon from '../svgs/moon-fill.svg'
import Check from '../svgs/check-double-line.svg'
import Fail from '../svgs/close-line.svg'
function InvoiceDefaultStatus ({ status }) {
return (
<div className='d-flex mt-2'>
<Moon className='spin fill-grey' />
<div className='ml-3 text-muted' style={{ fontWeight: '600' }}>{status}</div>
</div>
)
}
function InvoiceConfirmedStatus ({ status }) {
return (
<div className='d-flex mt-2'>
<Check className='fill-success' />
<div className='ml-3 text-success' style={{ fontWeight: '600' }}>{status}</div>
</div>
)
}
function InvoiceFailedStatus ({ status }) {
return (
<div className='d-flex mt-2'>
<Fail className='fill-danger' />
<div className='ml-3 text-danger' style={{ fontWeight: '600' }}>{status}</div>
</div>
)
}
export default function InvoiceStatus ({ variant, status }) {
switch (variant) {
case 'confirmed':
return <InvoiceConfirmedStatus status={status} />
case 'failed':
return <InvoiceFailedStatus status={status} />
default:
return <InvoiceDefaultStatus status={status} />
}
}

View File

@ -1,28 +1,20 @@
import QRCode from 'qrcode.react' import QRCode from 'qrcode.react'
import { InputGroup } from 'react-bootstrap' import { CopyInput, InputSkeleton } from './form'
import Moon from '../svgs/moon-fill.svg' import InvoiceStatus from './invoice-status'
import copy from 'clipboard-copy'
import Thumb from '../svgs/thumb-up-fill.svg'
import { useState } from 'react'
import BootstrapForm from 'react-bootstrap/Form'
import Button from 'react-bootstrap/Button'
import Check from '../svgs/check-double-line.svg'
import Fail from '../svgs/close-line.svg'
export function Invoice ({ invoice }) { export function Invoice ({ invoice }) {
const [copied, setCopied] = useState(false)
const qrValue = 'lightning:' + invoice.bolt11.toUpperCase() const qrValue = 'lightning:' + invoice.bolt11.toUpperCase()
let InvoiceStatus = InvoiceDefaultStatus let variant = 'default'
let status = 'waiting for you' let status = 'waiting for you'
if (invoice.confirmedAt) { if (invoice.confirmedAt) {
InvoiceStatus = InvoiceConfirmedStatus variant = 'confirmed'
status = `${invoice.msatsReceived / 1000} sats deposited` status = `${invoice.msatsReceived / 1000} sats deposited`
} else if (invoice.cancelled) { } else if (invoice.cancelled) {
InvoiceStatus = InvoiceFailedStatus variant = 'failed'
status = 'cancelled' status = 'cancelled'
} else if (invoice.expiresAt <= new Date()) { } else if (invoice.expiresAt <= new Date()) {
InvoiceStatus = InvoiceFailedStatus variant = 'failed'
status = 'expired' status = 'expired'
} }
@ -32,58 +24,21 @@ export function Invoice ({ invoice }) {
<QRCode className='h-auto mw-100' value={qrValue} renderAs='svg' size={300} /> <QRCode className='h-auto mw-100' value={qrValue} renderAs='svg' size={300} />
</div> </div>
<div className='mt-3 w-100'> <div className='mt-3 w-100'>
<InputGroup onClick={() => { <CopyInput type='text' placeholder={invoice.bolt11} readOnly />
copy(invoice.bolt11)
setCopied(true)
setTimeout(() => setCopied(false), 1500)
}}
>
<BootstrapForm.Control type='text' placeholder={invoice.bolt11} readOnly />
<InputGroup.Append>
<Button>{copied ? <Thumb width={20} height={20} /> : 'copy'}</Button>
</InputGroup.Append>
</InputGroup>
</div> </div>
<InvoiceStatus status={status} /> <InvoiceStatus variant={variant} status={status} />
</> </>
) )
} }
export function InvoiceDefaultStatus ({ status }) {
return (
<div className='d-flex mt-4'>
<Moon className='spin fill-grey' />
<div className='ml-3 text-muted' style={{ fontWeight: '600' }}>{status}</div>
</div>
)
}
export function InvoiceConfirmedStatus ({ status }) {
return (
<div className='d-flex mt-4'>
<Check className='fill-success' />
<div className='ml-3 text-success' style={{ fontWeight: '600' }}>{status}</div>
</div>
)
}
export function InvoiceFailedStatus ({ status }) {
return (
<div className='d-flex mt-4'>
<Fail className='fill-danger' />
<div className='ml-3 text-danger' style={{ fontWeight: '600' }}>{status}</div>
</div>
)
}
export function InvoiceSkeleton ({ status }) { export function InvoiceSkeleton ({ status }) {
return ( return (
<> <>
<div className='h-auto w-100 clouds' style={{ paddingTop: 'min(300px, 100%)', maxWidth: '300px' }} /> <div className='h-auto w-100 clouds' style={{ paddingTop: 'min(300px, 100%)', maxWidth: '300px' }} />
<div className='mt-3 w-100'> <div className='mt-3 w-100'>
<div className='w-100 clouds form-control' /> <InputSkeleton />
</div> </div>
<InvoiceDefaultStatus status={status} /> <InvoiceStatus variant='default' status={status} />
</> </>
) )
} }

View File

@ -6,6 +6,7 @@ import * as Yup from 'yup'
import { gql, useMutation, useQuery } from '@apollo/client' import { gql, useMutation, useQuery } from '@apollo/client'
import { InvoiceSkeleton } from '../components/invoice' import { InvoiceSkeleton } from '../components/invoice'
import LayoutCenter from '../components/layout-center' import LayoutCenter from '../components/layout-center'
import InputGroup from 'react-bootstrap/InputGroup'
export default function Wallet () { export default function Wallet () {
return ( return (
@ -73,7 +74,7 @@ export function FundForm () {
name='amount' name='amount'
required required
autoFocus autoFocus
append='sats' append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
/> />
<SubmitButton variant='success' className='mt-2'>generate invoice</SubmitButton> <SubmitButton variant='success' className='mt-2'>generate invoice</SubmitButton>
</Form> </Form>
@ -130,7 +131,7 @@ export function WithdrawlForm () {
label='max fee' label='max fee'
name='maxFee' name='maxFee'
required required
append='millisats' append={<InputGroup.Text className='text-monospace'>millisats</InputGroup.Text>}
/> />
<SubmitButton variant='success' className='mt-2'>withdrawl</SubmitButton> <SubmitButton variant='success' className='mt-2'>withdrawl</SubmitButton>
</Form> </Form>

View File

@ -1,6 +1,9 @@
import { useQuery } from '@apollo/client' import { useQuery } from '@apollo/client'
import gql from 'graphql-tag' import gql from 'graphql-tag'
import LayoutCenter from '../../components/layout-center' import LayoutCenter from '../../components/layout-center'
import { CopyInput, Input, InputSkeleton } from '../../components/form'
import InputGroup from 'react-bootstrap/InputGroup'
import InvoiceStatus from '../../components/invoice-status'
export async function getServerSideProps ({ params: { id } }) { export async function getServerSideProps ({ params: { id } }) {
return { return {
@ -15,6 +18,8 @@ export default function Withdrawl ({ id }) {
{ {
withdrawl(id: ${id}) { withdrawl(id: ${id}) {
bolt11 bolt11
msatsFeePaying
status
} }
}` }`
return ( return (
@ -28,8 +33,35 @@ function LoadWithdrawl ({ query }) {
const { loading, error, data } = useQuery(query, { pollInterval: 1000 }) const { loading, error, data } = useQuery(query, { pollInterval: 1000 })
if (error) return <div>error</div> if (error) return <div>error</div>
if (!data || loading) { if (!data || loading) {
return <div>withdrawl loading</div> return (
<>
<div className='w-100'>
<InputSkeleton label='invoice' />
</div>
<div className='w-100'>
<InputSkeleton label='max fee' />
</div>
<InvoiceStatus status='pending' />
</>
)
} }
return <div>hi</div> return (
<>
<div className='w-100'>
<CopyInput
label='invoice' type='text'
placeholder={data.withdrawl.bolt11} readOnly
/>
</div>
<div className='w-100'>
<Input
label='max fee' type='text'
placeholder={data.withdrawl.msatsFeePaying} readOnly
append={<InputGroup.Text className='text-monospace'>millisats</InputGroup.Text>}
/>
</div>
<InvoiceStatus status='pending' />
</>
)
} }