ready for invoices
@ -1,21 +1,13 @@
 | 
				
			|||||||
export default {
 | 
					export default {
 | 
				
			||||||
  Query: {
 | 
					  Query: {
 | 
				
			||||||
    accounts: async (parent, args, { lnd }) => {
 | 
					    invoice: async (parent, { id }, { me, models, lnd }) => {
 | 
				
			||||||
      console.log('hi')
 | 
					      return 'lnbc1500n1psfxyaypp5tmlgpudspqed4qf32xxmc7dhlqrd4glc09x794exz4t2pw8ms38sdpa2fjkzep6yptks7fqt9hh2gzwv4jkggz5dus9gatjdcsyzmrvypvk7atjypzx7cqzpgxqr23ssp529tup4vaxlxnst0lwh9kljpl9n6zg6n6vma5hw78lmnws32x278s9qyyssqxe73jclrlz3u7v7ruwee3n7h70ktsdsfmvpfjkccqxq5wg5h6njhqxar0a9fef5hd09ethwhvsj0dha2qy4tjjdxu08nkqymfs8wghqp6d7kth'
 | 
				
			||||||
      console.log(lnd.wallet.listAccounts)
 | 
					 | 
				
			||||||
      lnd.wallet.listAccounts({}, (err, res) => {
 | 
					 | 
				
			||||||
        console.log(err, res)
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
      return []
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Mutation: {
 | 
					  Mutation: {
 | 
				
			||||||
    createAccount: async (parent, args, { lnd }) => {
 | 
					    createInvoice: async (parent, { amount }, { me, models, lnd }) => {
 | 
				
			||||||
      lnd.default.newAddress({ type: 'p2wpkh', account: 'default' }, (err, res) => {
 | 
					      return 'lnbc1500n1psfxyaypp5tmlgpudspqed4qf32xxmc7dhlqrd4glc09x794exz4t2pw8ms38sdpa2fjkzep6yptks7fqt9hh2gzwv4jkggz5dus9gatjdcsyzmrvypvk7atjypzx7cqzpgxqr23ssp529tup4vaxlxnst0lwh9kljpl9n6zg6n6vma5hw78lmnws32x278s9qyyssqxe73jclrlz3u7v7ruwee3n7h70ktsdsfmvpfjkccqxq5wg5h6njhqxar0a9fef5hd09ethwhvsj0dha2qy4tjjdxu08nkqymfs8wghqp6d7kth'
 | 
				
			||||||
        console.log(err, res)
 | 
					 | 
				
			||||||
      })
 | 
					 | 
				
			||||||
      return 'ok'
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,10 +2,10 @@ import { gql } from 'apollo-server-micro'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default gql`
 | 
					export default gql`
 | 
				
			||||||
  extend type Query {
 | 
					  extend type Query {
 | 
				
			||||||
    accounts: [String!]
 | 
					    invoice(id: ID!): String!
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  extend type Mutation {
 | 
					  extend type Mutation {
 | 
				
			||||||
    createAccount: String!
 | 
					    createInvoice(amount: Int!): String!
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
				
			|||||||
@ -28,7 +28,7 @@ export function Input ({ label, prepend, append, hint, ...props }) {
 | 
				
			|||||||
      <InputGroup hasValidation>
 | 
					      <InputGroup hasValidation>
 | 
				
			||||||
        {prepend && (
 | 
					        {prepend && (
 | 
				
			||||||
          <InputGroup.Prepend>
 | 
					          <InputGroup.Prepend>
 | 
				
			||||||
            {prepend}
 | 
					            <InputGroup.Text>{prepend}</InputGroup.Text>
 | 
				
			||||||
          </InputGroup.Prepend>
 | 
					          </InputGroup.Prepend>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
        <BootstrapForm.Control
 | 
					        <BootstrapForm.Control
 | 
				
			||||||
@ -37,7 +37,7 @@ export function Input ({ label, prepend, append, hint, ...props }) {
 | 
				
			|||||||
        />
 | 
					        />
 | 
				
			||||||
        {append && (
 | 
					        {append && (
 | 
				
			||||||
          <InputGroup.Append>
 | 
					          <InputGroup.Append>
 | 
				
			||||||
            {append}
 | 
					            <InputGroup.Text>{append}</InputGroup.Text>
 | 
				
			||||||
          </InputGroup.Append>
 | 
					          </InputGroup.Append>
 | 
				
			||||||
        )}
 | 
					        )}
 | 
				
			||||||
        <BootstrapForm.Control.Feedback type='invalid'>
 | 
					        <BootstrapForm.Control.Feedback type='invalid'>
 | 
				
			||||||
 | 
				
			|||||||
@ -20,18 +20,29 @@ export default function Header () {
 | 
				
			|||||||
    if (session) {
 | 
					    if (session) {
 | 
				
			||||||
      return (
 | 
					      return (
 | 
				
			||||||
        <div className='d-flex align-items-center'>
 | 
					        <div className='d-flex align-items-center'>
 | 
				
			||||||
          <NavDropdown title={`@${session.user.name}`} alignRight>
 | 
					          <NavDropdown className='pl-0' title={`@${session.user.name}`} alignRight>
 | 
				
			||||||
            <Link href={'/' + session.user.name} passHref>
 | 
					            <Link href={'/' + session.user.name} passHref>
 | 
				
			||||||
              <NavDropdown.Item>profile</NavDropdown.Item>
 | 
					              <NavDropdown.Item>profile</NavDropdown.Item>
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
            <Link href='/fund' passHref>
 | 
					            <Link href='/wallet' passHref>
 | 
				
			||||||
              <NavDropdown.Item className='text-success'>fund [0,0]</NavDropdown.Item>
 | 
					              <NavDropdown.Item>wallet</NavDropdown.Item>
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
 | 
					            <div>
 | 
				
			||||||
 | 
					              <NavDropdown.Divider />
 | 
				
			||||||
 | 
					              <Link href='/recent' passHref>
 | 
				
			||||||
 | 
					                <NavDropdown.Item>recent</NavDropdown.Item>
 | 
				
			||||||
 | 
					              </Link>
 | 
				
			||||||
 | 
					              <Link href='/post' passHref>
 | 
				
			||||||
 | 
					                <NavDropdown.Item>post</NavDropdown.Item>
 | 
				
			||||||
 | 
					              </Link>
 | 
				
			||||||
 | 
					              <NavDropdown.Item href='https://bitcoinerjobs.co' target='_blank'>jobs</NavDropdown.Item>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <NavDropdown.Divider />
 | 
				
			||||||
            <NavDropdown.Item onClick={signOut}>logout</NavDropdown.Item>
 | 
					            <NavDropdown.Item onClick={signOut}>logout</NavDropdown.Item>
 | 
				
			||||||
          </NavDropdown>
 | 
					          </NavDropdown>
 | 
				
			||||||
          <Nav.Item>
 | 
					          <Nav.Item>
 | 
				
			||||||
            <Link href='/fund' passHref>
 | 
					            <Link href='/wallet' passHref>
 | 
				
			||||||
              <Nav.Link className='text-success pl-0'>[0,0]</Nav.Link>
 | 
					              <Nav.Link className='text-success px-0'>[0,0]</Nav.Link>
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
          </Nav.Item>
 | 
					          </Nav.Item>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
@ -47,22 +58,22 @@ export default function Header () {
 | 
				
			|||||||
        <Navbar className={styles.navbar}>
 | 
					        <Navbar className={styles.navbar}>
 | 
				
			||||||
          <Nav className='w-100 justify-content-between flex-wrap align-items-center' activeKey={path}>
 | 
					          <Nav className='w-100 justify-content-between flex-wrap align-items-center' activeKey={path}>
 | 
				
			||||||
            <Link href='/' passHref>
 | 
					            <Link href='/' passHref>
 | 
				
			||||||
              <Navbar.Brand className={`${styles.brand} mr-2 d-none d-sm-block`}>STACKER NEWS</Navbar.Brand>
 | 
					              <Navbar.Brand className={`${styles.brand} d-none d-sm-block`}>STACKER NEWS</Navbar.Brand>
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
            <Link href='/' passHref>
 | 
					            <Link href='/' passHref>
 | 
				
			||||||
              <Navbar.Brand className={`${styles.brand} mr-2 d-block d-sm-none`}>SN</Navbar.Brand>
 | 
					              <Navbar.Brand className={`${styles.brand} d-block d-sm-none`}>SN</Navbar.Brand>
 | 
				
			||||||
            </Link>
 | 
					            </Link>
 | 
				
			||||||
            <Nav.Item>
 | 
					            <Nav.Item className='d-md-flex d-none'>
 | 
				
			||||||
              <Link href='/recent' passHref>
 | 
					              <Link href='/recent' passHref>
 | 
				
			||||||
                <Nav.Link className={styles.navLink}>recent</Nav.Link>
 | 
					                <Nav.Link className={styles.navLink}>recent</Nav.Link>
 | 
				
			||||||
              </Link>
 | 
					              </Link>
 | 
				
			||||||
            </Nav.Item>
 | 
					            </Nav.Item>
 | 
				
			||||||
            <Nav.Item>
 | 
					            <Nav.Item className='d-md-flex d-none'>
 | 
				
			||||||
              <Link href='/post' passHref>
 | 
					              <Link href='/post' passHref>
 | 
				
			||||||
                <Nav.Link className={styles.navLink}>post</Nav.Link>
 | 
					                <Nav.Link className={styles.navLink}>post</Nav.Link>
 | 
				
			||||||
              </Link>
 | 
					              </Link>
 | 
				
			||||||
            </Nav.Item>
 | 
					            </Nav.Item>
 | 
				
			||||||
            <Nav.Item>
 | 
					            <Nav.Item className='d-md-flex d-none'>
 | 
				
			||||||
              <Nav.Link href='https://bitcoinerjobs.co' target='_blank' className={styles.navLink}>jobs</Nav.Link>
 | 
					              <Nav.Link href='https://bitcoinerjobs.co' target='_blank' className={styles.navLink}>jobs</Nav.Link>
 | 
				
			||||||
            </Nav.Item>
 | 
					            </Nav.Item>
 | 
				
			||||||
            <Nav.Item style={{ fontFamily: 'monospace', opacity: '.5' }}>
 | 
					            <Nav.Item style={{ fontFamily: 'monospace', opacity: '.5' }}>
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,56 @@
 | 
				
			|||||||
 | 
					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'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function Invoice ({ invoice }) {
 | 
				
			||||||
 | 
					  const [copied, setCopied] = useState(false)
 | 
				
			||||||
 | 
					  const qrValue = 'lightning:' + invoice.toUpperCase()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <>
 | 
				
			||||||
 | 
					      <div>
 | 
				
			||||||
 | 
					        <QRCode className='h-auto mw-100' value={qrValue} size={300} />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <div className='mt-3 w-100'>
 | 
				
			||||||
 | 
					        <InputGroup onClick={() => {
 | 
				
			||||||
 | 
					          copy(invoice)
 | 
				
			||||||
 | 
					          setCopied(true)
 | 
				
			||||||
 | 
					          setTimeout(() => setCopied(false), 1500)
 | 
				
			||||||
 | 
					        }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <BootstrapForm.Control type='text' placeholder={invoice} readOnly />
 | 
				
			||||||
 | 
					          <InputGroup.Append>
 | 
				
			||||||
 | 
					            <Button>{copied ? <Thumb width={20} height={20} /> : 'copy'}</Button>
 | 
				
			||||||
 | 
					          </InputGroup.Append>
 | 
				
			||||||
 | 
					        </InputGroup>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <InvoiceStatus />
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function InvoiceStatus ({ skeleton }) {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className='d-flex mt-4'>
 | 
				
			||||||
 | 
					      <Moon className='spin fill-grey' />
 | 
				
			||||||
 | 
					      <div className='ml-3 text-muted' style={{ fontWeight: '600' }}>{skeleton ? 'generating' : 'waiting for you'}</div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function InvoiceSkeleton () {
 | 
				
			||||||
 | 
					  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' />
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					      <InvoiceStatus skeleton />
 | 
				
			||||||
 | 
					    </>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										0
									
								
								components/invoice.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -6,7 +6,7 @@ export default function Items ({ query, rank }) {
 | 
				
			|||||||
  const { loading, error, data } = useQuery(query)
 | 
					  const { loading, error, data } = useQuery(query)
 | 
				
			||||||
  if (error) return <div>Failed to load!</div>
 | 
					  if (error) return <div>Failed to load!</div>
 | 
				
			||||||
  if (loading) {
 | 
					  if (loading) {
 | 
				
			||||||
    const items = new Array(30).fill(null)
 | 
					    const items = new Array(20).fill(null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
      <div className={styles.grid}>
 | 
					      <div className={styles.grid}>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								components/layout-center.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					import Layout from './layout'
 | 
				
			||||||
 | 
					import styles from './layout-center.module.css'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function LayoutCenter ({ children }) {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <div className={styles.page}>
 | 
				
			||||||
 | 
					      <Layout noContain>
 | 
				
			||||||
 | 
					        <div className={styles.content}>
 | 
				
			||||||
 | 
					          {children}
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </Layout>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								components/layout-center.module.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					.page {
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    flex-flow: column;
 | 
				
			||||||
 | 
					    height: 100%;
 | 
				
			||||||
 | 
					    min-height: 100vh;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.content {
 | 
				
			||||||
 | 
					    flex-grow: 1;
 | 
				
			||||||
 | 
					    display: flex;
 | 
				
			||||||
 | 
					    align-items: center;
 | 
				
			||||||
 | 
					    justify-content: center;
 | 
				
			||||||
 | 
					    max-width: 740px;
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					    padding-right: 15px;
 | 
				
			||||||
 | 
					    padding-left: 15px;
 | 
				
			||||||
 | 
					    flex-direction: column;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.content form {
 | 
				
			||||||
 | 
					    width: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -12,6 +12,7 @@
 | 
				
			|||||||
    "@prisma/client": "^2.19.0",
 | 
					    "@prisma/client": "^2.19.0",
 | 
				
			||||||
    "apollo-server-micro": "^2.21.2",
 | 
					    "apollo-server-micro": "^2.21.2",
 | 
				
			||||||
    "bootstrap": "^4.6.0",
 | 
					    "bootstrap": "^4.6.0",
 | 
				
			||||||
 | 
					    "clipboard-copy": "^4.0.1",
 | 
				
			||||||
    "formik": "^2.2.6",
 | 
					    "formik": "^2.2.6",
 | 
				
			||||||
    "graphql": "^15.5.0",
 | 
					    "graphql": "^15.5.0",
 | 
				
			||||||
    "ln-service": "^51.7.0",
 | 
					    "ln-service": "^51.7.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +0,0 @@
 | 
				
			|||||||
import Layout from '../components/layout'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default function Fund () {
 | 
					 | 
				
			||||||
  return (
 | 
					 | 
				
			||||||
    <Layout>
 | 
					 | 
				
			||||||
      <div>fund</div>
 | 
					 | 
				
			||||||
    </Layout>
 | 
					 | 
				
			||||||
  )
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										34
									
								
								pages/invoices/[id].js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					import { useQuery } from '@apollo/client'
 | 
				
			||||||
 | 
					import gql from 'graphql-tag'
 | 
				
			||||||
 | 
					import { Invoice, InvoiceSkeleton } from '../../components/invoice'
 | 
				
			||||||
 | 
					import LayoutCenter from '../../components/layout-center'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export async function getServerSideProps ({ params: { id } }) {
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    props: {
 | 
				
			||||||
 | 
					      id
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function FullInvoice ({ id }) {
 | 
				
			||||||
 | 
					  const query = gql`
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      invoice(id: ${id})
 | 
				
			||||||
 | 
					    }`
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <LayoutCenter>
 | 
				
			||||||
 | 
					      <LoadInvoice query={query} />
 | 
				
			||||||
 | 
					    </LayoutCenter>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function LoadInvoice ({ query }) {
 | 
				
			||||||
 | 
					  const { loading, error, data } = useQuery(query)
 | 
				
			||||||
 | 
					  if (error) return <div>error</div>
 | 
				
			||||||
 | 
					  if (!data || loading) {
 | 
				
			||||||
 | 
					    return <InvoiceSkeleton />
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return <Invoice invoice={data.invoice} />
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,5 +1,4 @@
 | 
				
			|||||||
import { providers, signIn, getSession, csrfToken } from 'next-auth/client'
 | 
					import { providers, signIn, getSession, csrfToken } from 'next-auth/client'
 | 
				
			||||||
import Layout from '../components/layout'
 | 
					 | 
				
			||||||
import Button from 'react-bootstrap/Button'
 | 
					import Button from 'react-bootstrap/Button'
 | 
				
			||||||
import styles from '../styles/login.module.css'
 | 
					import styles from '../styles/login.module.css'
 | 
				
			||||||
import GithubIcon from '../svgs/github-fill.svg'
 | 
					import GithubIcon from '../svgs/github-fill.svg'
 | 
				
			||||||
@ -8,6 +7,7 @@ import { Input, SubmitButton, SyncForm } from '../components/form'
 | 
				
			|||||||
import * as Yup from 'yup'
 | 
					import * as Yup from 'yup'
 | 
				
			||||||
import { useState } from 'react'
 | 
					import { useState } from 'react'
 | 
				
			||||||
import Alert from 'react-bootstrap/Alert'
 | 
					import Alert from 'react-bootstrap/Alert'
 | 
				
			||||||
 | 
					import LayoutCenter from '../components/layout-center'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export async function getServerSideProps ({ req, res, query: { callbackUrl, error = null } }) {
 | 
					export async function getServerSideProps ({ req, res, query: { callbackUrl, error = null } }) {
 | 
				
			||||||
  const session = await getSession({ req })
 | 
					  const session = await getSession({ req })
 | 
				
			||||||
@ -50,8 +50,7 @@ export default function login ({ providers, csrfToken, error }) {
 | 
				
			|||||||
  const [errorMessage, setErrorMessage] = useState(error && (errors[error] ?? errors.default))
 | 
					  const [errorMessage, setErrorMessage] = useState(error && (errors[error] ?? errors.default))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Layout noContain>
 | 
					    <LayoutCenter>
 | 
				
			||||||
      <div className={styles.page}>
 | 
					 | 
				
			||||||
      <div className={styles.login}>
 | 
					      <div className={styles.login}>
 | 
				
			||||||
        {errorMessage &&
 | 
					        {errorMessage &&
 | 
				
			||||||
          <Alert variant='danger' onClose={() => setErrorMessage(undefined)} dismissible>{errorMessage}</Alert>}
 | 
					          <Alert variant='danger' onClose={() => setErrorMessage(undefined)} dismissible>{errorMessage}</Alert>}
 | 
				
			||||||
@ -96,7 +95,6 @@ export default function login ({ providers, csrfToken, error }) {
 | 
				
			|||||||
          <SubmitButton variant='secondary' className={styles.providerButton}>Login with Email</SubmitButton>
 | 
					          <SubmitButton variant='secondary' className={styles.providerButton}>Login with Email</SubmitButton>
 | 
				
			||||||
        </SyncForm>
 | 
					        </SyncForm>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      </div>
 | 
					    </LayoutCenter>
 | 
				
			||||||
    </Layout>
 | 
					 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,10 @@
 | 
				
			|||||||
import Layout from '../components/layout'
 | 
					 | 
				
			||||||
import Button from 'react-bootstrap/Button'
 | 
					import Button from 'react-bootstrap/Button'
 | 
				
			||||||
import { Form, Input, SubmitButton } from '../components/form'
 | 
					import { Form, Input, SubmitButton } from '../components/form'
 | 
				
			||||||
import { useRouter } from 'next/router'
 | 
					import { useRouter } from 'next/router'
 | 
				
			||||||
import Link from 'next/link'
 | 
					import Link from 'next/link'
 | 
				
			||||||
import styles from '../styles/post.module.css'
 | 
					 | 
				
			||||||
import * as Yup from 'yup'
 | 
					import * as Yup from 'yup'
 | 
				
			||||||
import { gql, useMutation } from '@apollo/client'
 | 
					import { gql, useMutation } from '@apollo/client'
 | 
				
			||||||
 | 
					import LayoutCenter from '../components/layout-center'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const DiscussionSchema = Yup.object({
 | 
					export const DiscussionSchema = Yup.object({
 | 
				
			||||||
  title: Yup.string().required('required').trim()
 | 
					  title: Yup.string().required('required').trim()
 | 
				
			||||||
@ -127,12 +126,8 @@ export function PostForm () {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
export default function Post () {
 | 
					export default function Post () {
 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    <Layout noContain>
 | 
					    <LayoutCenter>
 | 
				
			||||||
      <div className={styles.page}>
 | 
					 | 
				
			||||||
        <div className={styles.post}>
 | 
					 | 
				
			||||||
      <PostForm />
 | 
					      <PostForm />
 | 
				
			||||||
        </div>
 | 
					    </LayoutCenter>
 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </Layout>
 | 
					 | 
				
			||||||
  )
 | 
					  )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										82
									
								
								pages/wallet.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,82 @@
 | 
				
			|||||||
 | 
					import { useRouter } from 'next/router'
 | 
				
			||||||
 | 
					import { Form, Input, SubmitButton } from '../components/form'
 | 
				
			||||||
 | 
					import Link from 'next/link'
 | 
				
			||||||
 | 
					import Button from 'react-bootstrap/Button'
 | 
				
			||||||
 | 
					import * as Yup from 'yup'
 | 
				
			||||||
 | 
					import { gql, useMutation } from '@apollo/client'
 | 
				
			||||||
 | 
					import { InvoiceSkeleton } from '../components/invoice'
 | 
				
			||||||
 | 
					import LayoutCenter from '../components/layout-center'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default function Wallet () {
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <LayoutCenter>
 | 
				
			||||||
 | 
					      <WalletForm />
 | 
				
			||||||
 | 
					    </LayoutCenter>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function WalletForm () {
 | 
				
			||||||
 | 
					  const router = useRouter()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (!router.query.type) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					      <div className='align-items-center'>
 | 
				
			||||||
 | 
					        <Link href='/wallet?type=fund'>
 | 
				
			||||||
 | 
					          <Button variant='success'>fund</Button>
 | 
				
			||||||
 | 
					        </Link>
 | 
				
			||||||
 | 
					        <span className='mx-3 font-weight-bold text-muted'>or</span>
 | 
				
			||||||
 | 
					        <Link href='/wallet?type=withdrawl'>
 | 
				
			||||||
 | 
					          <Button variant='success'>withdrawl</Button>
 | 
				
			||||||
 | 
					        </Link>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (router.query.type === 'fund') {
 | 
				
			||||||
 | 
					    return <FundForm />
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    return <WithdrawlForm />
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const FundSchema = Yup.object({
 | 
				
			||||||
 | 
					  amount: Yup.number('must be a number').required('required').positive('must be positive').integer('must be whole')
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function FundForm () {
 | 
				
			||||||
 | 
					  const router = useRouter()
 | 
				
			||||||
 | 
					  const [createInvoice, { called }] = useMutation(gql`
 | 
				
			||||||
 | 
					    mutation createInvoice($amount: Int!) {
 | 
				
			||||||
 | 
					      createInvoice(amount: $amount)
 | 
				
			||||||
 | 
					    }`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (called) {
 | 
				
			||||||
 | 
					    return <InvoiceSkeleton />
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return (
 | 
				
			||||||
 | 
					    <Form
 | 
				
			||||||
 | 
					      initial={{
 | 
				
			||||||
 | 
					        amount: 1000
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					      schema={FundSchema}
 | 
				
			||||||
 | 
					      onSubmit={async ({ amount }) => {
 | 
				
			||||||
 | 
					        await createInvoice({ variables: { amount } })
 | 
				
			||||||
 | 
					        router.push('/invoices/1')
 | 
				
			||||||
 | 
					      }}
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <Input
 | 
				
			||||||
 | 
					        label='amount'
 | 
				
			||||||
 | 
					        name='amount'
 | 
				
			||||||
 | 
					        required
 | 
				
			||||||
 | 
					        autoFocus
 | 
				
			||||||
 | 
					        append='sats'
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <SubmitButton variant='success' className='mt-2'>generate invoice</SubmitButton>
 | 
				
			||||||
 | 
					    </Form>
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function WithdrawlForm () {
 | 
				
			||||||
 | 
					  return <div>withdrawl</div>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								public/giphy.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 936 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								public/static.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 14 KiB  | 
@ -57,8 +57,6 @@ body {
 | 
				
			|||||||
  background-attachment:fixed;
 | 
					  background-attachment:fixed;
 | 
				
			||||||
  min-height: 100vh;
 | 
					  min-height: 100vh;
 | 
				
			||||||
  height: 100%;
 | 
					  height: 100%;
 | 
				
			||||||
  z-index: -2;
 | 
					 | 
				
			||||||
  position: relative;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.form-label {
 | 
					.form-label {
 | 
				
			||||||
@ -109,6 +107,10 @@ body {
 | 
				
			|||||||
  font-weight: bold;
 | 
					  font-weight: bold;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.fill-grey {
 | 
				
			||||||
 | 
					  fill: grey;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@keyframes flash {
 | 
					@keyframes flash {
 | 
				
			||||||
	from { filter: brightness(1);}
 | 
						from { filter: brightness(1);}
 | 
				
			||||||
  2% { filter: brightness(2.3); }
 | 
					  2% { filter: brightness(2.3); }
 | 
				
			||||||
@ -126,5 +128,24 @@ body {
 | 
				
			|||||||
  background-origin: content-box;
 | 
					  background-origin: content-box;
 | 
				
			||||||
  background-size: cover;
 | 
					  background-size: cover;
 | 
				
			||||||
  background-attachment: fixed;
 | 
					  background-attachment: fixed;
 | 
				
			||||||
  opacity: .2;
 | 
					  opacity: .1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@keyframes spin {
 | 
				
			||||||
 | 
					  0% { transform: rotate(0deg); }
 | 
				
			||||||
 | 
					  100% {  transform: rotate(359deg); }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.spin {
 | 
				
			||||||
 | 
					  animation: spin 2s linear infinite;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.static {
 | 
				
			||||||
 | 
					  background: url('/giphy.gif');
 | 
				
			||||||
 | 
					  background-color: grey;
 | 
				
			||||||
 | 
					  background-repeat: repeat;
 | 
				
			||||||
 | 
					  background-origin: content-box;
 | 
				
			||||||
 | 
					  background-size: cover;
 | 
				
			||||||
 | 
					  background-attachment: fixed;
 | 
				
			||||||
 | 
					  opacity: .1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -5,23 +5,6 @@
 | 
				
			|||||||
    display: flex;
 | 
					    display: flex;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.page {
 | 
					 | 
				
			||||||
    position: absolute;
 | 
					 | 
				
			||||||
    width: 100%;
 | 
					 | 
				
			||||||
    height: 100%;
 | 
					 | 
				
			||||||
    display: table;
 | 
					 | 
				
			||||||
    margin: 0;
 | 
					 | 
				
			||||||
    padding: 0;
 | 
					 | 
				
			||||||
    top: 0;
 | 
					 | 
				
			||||||
    z-index: -1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.login {
 | 
					 | 
				
			||||||
    display: table-cell;
 | 
					 | 
				
			||||||
    vertical-align: middle;
 | 
					 | 
				
			||||||
    padding: .5rem;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.login > * {
 | 
					.login > * {
 | 
				
			||||||
    max-width: 300px;
 | 
					    max-width: 300px;
 | 
				
			||||||
    margin: auto;
 | 
					    margin: auto;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,29 +0,0 @@
 | 
				
			|||||||
.page {
 | 
					 | 
				
			||||||
    position: absolute;
 | 
					 | 
				
			||||||
    width: 100%;
 | 
					 | 
				
			||||||
    height: 100%;
 | 
					 | 
				
			||||||
    display: table;
 | 
					 | 
				
			||||||
    margin: 0;
 | 
					 | 
				
			||||||
    padding: 0;
 | 
					 | 
				
			||||||
    top: 0;
 | 
					 | 
				
			||||||
    z-index: -1;
 | 
					 | 
				
			||||||
    padding-right: 15px;
 | 
					 | 
				
			||||||
    padding-left: 15px
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.post {
 | 
					 | 
				
			||||||
    display: table-cell;
 | 
					 | 
				
			||||||
    vertical-align: middle;
 | 
					 | 
				
			||||||
    padding: .5rem;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.post > form {
 | 
					 | 
				
			||||||
    max-width: 740px;
 | 
					 | 
				
			||||||
    margin: 1rem auto;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.post > div {
 | 
					 | 
				
			||||||
    display: flex;
 | 
					 | 
				
			||||||
    justify-content: center;
 | 
					 | 
				
			||||||
    margin: 1rem auto;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								svgs/bit-coin-fill.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-6v2h2v-2h1a2.5 2.5 0 0 0 2-4 2.5 2.5 0 0 0-2-4h-1V6h-2v2H8v8h3zm-1-3h4a.5.5 0 1 1 0 1h-4v-1zm0-3h4a.5.5 0 1 1 0 1h-4v-1z"/></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 335 B  | 
							
								
								
									
										1
									
								
								svgs/coin-fill.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M23 12v2c0 3.314-4.925 6-11 6-5.967 0-10.824-2.591-10.995-5.823L1 14v-2c0 3.314 4.925 6 11 6s11-2.686 11-6zM12 4c6.075 0 11 2.686 11 6s-4.925 6-11 6-11-2.686-11-6 4.925-6 11-6z"/></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 314 B  | 
							
								
								
									
										1
									
								
								svgs/hand-coin-fill.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M9.33 11.5h2.17A4.5 4.5 0 0 1 16 16H8.999L9 17h8v-1a5.578 5.578 0 0 0-.886-3H19a5 5 0 0 1 4.516 2.851C21.151 18.972 17.322 21 13 21c-2.761 0-5.1-.59-7-1.625L6 10.071A6.967 6.967 0 0 1 9.33 11.5zM5 19a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1v-9a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v9zM18 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6zm-7-3a3 3 0 1 1 0 6 3 3 0 0 1 0-6z"/></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 471 B  | 
							
								
								
									
										1
									
								
								svgs/moon-fill.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.38 2.019a7.5 7.5 0 1 0 10.6 10.6C21.662 17.854 17.316 22 12.001 22 6.477 22 2 17.523 2 12c0-5.315 4.146-9.661 9.38-9.981z"/></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 263 B  | 
							
								
								
									
										1
									
								
								svgs/thumb-up-fill.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M2 9h3v12H2a1 1 0 0 1-1-1V10a1 1 0 0 1 1-1zm5.293-1.293l6.4-6.4a.5.5 0 0 1 .654-.047l.853.64a1.5 1.5 0 0 1 .553 1.57L14.6 8H21a2 2 0 0 1 2 2v2.104a2 2 0 0 1-.15.762l-3.095 7.515a1 1 0 0 1-.925.619H8a1 1 0 0 1-1-1V8.414a1 1 0 0 1 .293-.707z"/></svg>
 | 
				
			||||||
| 
		 After Width: | Height: | Size: 377 B  | 
@ -1577,6 +1577,11 @@ cli-highlight@^2.1.10:
 | 
				
			|||||||
    parse5-htmlparser2-tree-adapter "^6.0.0"
 | 
					    parse5-htmlparser2-tree-adapter "^6.0.0"
 | 
				
			||||||
    yargs "^16.0.0"
 | 
					    yargs "^16.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					clipboard-copy@^4.0.1:
 | 
				
			||||||
 | 
					  version "4.0.1"
 | 
				
			||||||
 | 
					  resolved "https://registry.yarnpkg.com/clipboard-copy/-/clipboard-copy-4.0.1.tgz#326ef9726d4ffe72d9a82a7bbe19379de692017d"
 | 
				
			||||||
 | 
					  integrity sha512-wOlqdqziE/NNTUJsfSgXmBMIrYmfd5V0HCGsR8uAKHcg+h9NENWINcfRjtWGU77wDHC8B8ijV4hMTGYbrKovng==
 | 
				
			||||||
 | 
					
 | 
				
			||||||
cliui@^7.0.2:
 | 
					cliui@^7.0.2:
 | 
				
			||||||
  version "7.0.4"
 | 
					  version "7.0.4"
 | 
				
			||||||
  resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
 | 
					  resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
 | 
				
			||||||
 | 
				
			|||||||