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
msatsFeePaying: 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 { Formik, Form as FormikForm, useFormikContext, useField } from 'formik'
import { useRef, useState } from 'react'
import copy from 'clipboard-copy'
import Thumb from '../svgs/thumb-up-fill.svg'
export function SubmitButton ({ children, variant, ...props }) {
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 }) {
const [field, meta] = useField(props)
const [field, meta] = props.readOnly ? [{}, {}] : useField(props)
return (
<BootstrapForm.Group>
@ -28,7 +57,7 @@ export function Input ({ label, prepend, append, hint, ...props }) {
<InputGroup hasValidation>
{prepend && (
<InputGroup.Prepend>
<InputGroup.Text>{prepend}</InputGroup.Text>
{prepend}
</InputGroup.Prepend>
)}
<BootstrapForm.Control
@ -37,7 +66,7 @@ export function Input ({ label, prepend, append, hint, ...props }) {
/>
{append && (
<InputGroup.Append>
<InputGroup.Text>{append}</InputGroup.Text>
{append}
</InputGroup.Append>
)}
<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 { InputGroup } from 'react-bootstrap'
import Moon from '../svgs/moon-fill.svg'
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'
import { CopyInput, InputSkeleton } from './form'
import InvoiceStatus from './invoice-status'
export function Invoice ({ invoice }) {
const [copied, setCopied] = useState(false)
const qrValue = 'lightning:' + invoice.bolt11.toUpperCase()
let InvoiceStatus = InvoiceDefaultStatus
let variant = 'default'
let status = 'waiting for you'
if (invoice.confirmedAt) {
InvoiceStatus = InvoiceConfirmedStatus
variant = 'confirmed'
status = `${invoice.msatsReceived / 1000} sats deposited`
} else if (invoice.cancelled) {
InvoiceStatus = InvoiceFailedStatus
variant = 'failed'
status = 'cancelled'
} else if (invoice.expiresAt <= new Date()) {
InvoiceStatus = InvoiceFailedStatus
variant = 'failed'
status = 'expired'
}
@ -32,58 +24,21 @@ export function Invoice ({ invoice }) {
<QRCode className='h-auto mw-100' value={qrValue} renderAs='svg' size={300} />
</div>
<div className='mt-3 w-100'>
<InputGroup onClick={() => {
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>
<CopyInput type='text' placeholder={invoice.bolt11} readOnly />
</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 }) {
return (
<>
<div className='h-auto w-100 clouds' style={{ paddingTop: 'min(300px, 100%)', maxWidth: '300px' }} />
<div className='mt-3 w-100'>
<div className='w-100 clouds form-control' />
<InputSkeleton />
</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 { InvoiceSkeleton } from '../components/invoice'
import LayoutCenter from '../components/layout-center'
import InputGroup from 'react-bootstrap/InputGroup'
export default function Wallet () {
return (
@ -73,7 +74,7 @@ export function FundForm () {
name='amount'
required
autoFocus
append='sats'
append={<InputGroup.Text className='text-monospace'>sats</InputGroup.Text>}
/>
<SubmitButton variant='success' className='mt-2'>generate invoice</SubmitButton>
</Form>
@ -130,7 +131,7 @@ export function WithdrawlForm () {
label='max fee'
name='maxFee'
required
append='millisats'
append={<InputGroup.Text className='text-monospace'>millisats</InputGroup.Text>}
/>
<SubmitButton variant='success' className='mt-2'>withdrawl</SubmitButton>
</Form>

View File

@ -1,6 +1,9 @@
import { useQuery } from '@apollo/client'
import gql from 'graphql-tag'
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 } }) {
return {
@ -15,6 +18,8 @@ export default function Withdrawl ({ id }) {
{
withdrawl(id: ${id}) {
bolt11
msatsFeePaying
status
}
}`
return (
@ -28,8 +33,35 @@ function LoadWithdrawl ({ query }) {
const { loading, error, data } = useQuery(query, { pollInterval: 1000 })
if (error) return <div>error</div>
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' />
</>
)
}