lightning login copy
This commit is contained in:
parent
d1a08eda36
commit
e2d7506ebf
|
@ -3,7 +3,7 @@ import ArrowRight from '../svgs/arrow-right-s-fill.svg'
|
|||
import ArrowDown from '../svgs/arrow-down-s-fill.svg'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export default function AccordianItem ({ header, body, headerColor = 'var(--theme-grey)', show }) {
|
||||
export default function AccordianItem ({ header, body, className, headerColor = 'var(--theme-grey)', show }) {
|
||||
const [open, setOpen] = useState(show)
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -19,6 +19,7 @@ export default function AccordianItem ({ header, body, headerColor = 'var(--them
|
|||
eventKey='0'
|
||||
style={{ cursor: 'pointer', display: 'flex', alignItems: 'center' }}
|
||||
onClick={() => setOpen(!open)}
|
||||
className={className}
|
||||
>
|
||||
{open
|
||||
? <ArrowDown style={{ fill: headerColor }} height={20} width={20} />
|
||||
|
|
|
@ -4,7 +4,7 @@ import ThumbDown from '../svgs/thumb-down-fill.svg'
|
|||
|
||||
function InvoiceDefaultStatus ({ status }) {
|
||||
return (
|
||||
<div className='d-flex mt-2'>
|
||||
<div className='d-flex mt-2 justify-content-center'>
|
||||
<Moon className='spin fill-grey' />
|
||||
<div className='ml-3 text-muted' style={{ fontWeight: '600' }}>{status}</div>
|
||||
</div>
|
||||
|
@ -13,7 +13,7 @@ function InvoiceDefaultStatus ({ status }) {
|
|||
|
||||
function InvoiceConfirmedStatus ({ status }) {
|
||||
return (
|
||||
<div className='d-flex mt-2'>
|
||||
<div className='d-flex mt-2 justify-content-center'>
|
||||
<Check className='fill-success' />
|
||||
<div className='ml-3 text-success' style={{ fontWeight: '600' }}>{status}</div>
|
||||
</div>
|
||||
|
@ -22,7 +22,7 @@ function InvoiceConfirmedStatus ({ status }) {
|
|||
|
||||
function InvoiceFailedStatus ({ status }) {
|
||||
return (
|
||||
<div className='d-flex mt-2'>
|
||||
<div className='d-flex mt-2 justify-content-center'>
|
||||
<ThumbDown className='fill-danger' />
|
||||
<div className='ml-3 text-danger' style={{ fontWeight: '600' }}>{status}</div>
|
||||
</div>
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import { gql, useMutation, useQuery } from '@apollo/client'
|
||||
import { signIn } from 'next-auth/client'
|
||||
import { useEffect } from 'react'
|
||||
import { Col, Container, Row } from 'react-bootstrap'
|
||||
import AccordianItem from './accordian-item'
|
||||
import LnQR, { LnQRSkeleton } from './lnqr'
|
||||
import styles from './lightning-auth.module.css'
|
||||
import BackIcon from '../svgs/arrow-left-line.svg'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
function LnQRAuth ({ k1, encodedUrl, callbackUrl }) {
|
||||
const query = gql`
|
||||
|
@ -19,16 +24,67 @@ function LnQRAuth ({ k1, encodedUrl, callbackUrl }) {
|
|||
|
||||
// output pubkey and k1
|
||||
return (
|
||||
<>
|
||||
<small className='mb-2'>
|
||||
<a className='text-muted text-underline' href='https://github.com/fiatjaf/lnurl-rfc#lnurl-documents' target='_blank' rel='noreferrer' style={{ textDecoration: 'underline' }}>Does my wallet support lnurl-auth?</a>
|
||||
</small>
|
||||
<LnQR value={encodedUrl} status='waiting for you' />
|
||||
</>
|
||||
<LnQR value={encodedUrl} status='waiting for you' />
|
||||
)
|
||||
}
|
||||
|
||||
export function LightningAuth ({ callbackUrl }) {
|
||||
function LightningExplainer ({ text, children }) {
|
||||
const router = useRouter()
|
||||
return (
|
||||
<Container sm>
|
||||
<div className={styles.login}>
|
||||
<div className='w-100 mb-3 text-muted pointer' onClick={() => router.back()}><BackIcon /></div>
|
||||
<h3 className='w-100 pb-2'>
|
||||
{text || 'Login'} with Lightning
|
||||
</h3>
|
||||
<div className='font-weight-bold text-muted pb-4'>This is the most private way to use Stacker News. Just open your Lightning wallet and scan the QR code.</div>
|
||||
<Row className='w-100 text-muted'>
|
||||
<Col className='pl-0 mb-4' md>
|
||||
<AccordianItem
|
||||
header={`Which wallets can I use to ${(text || 'Login').toLowerCase()}?`}
|
||||
body={
|
||||
<>
|
||||
<Row className='mb-3 no-gutters'>
|
||||
You can use any wallet that support lnurl-auth. These are some wallets you can use:
|
||||
</Row>
|
||||
<Row>
|
||||
<Col xs>
|
||||
<ul className='mb-0'>
|
||||
<li>Alby</li>
|
||||
<li>Balance of Satoshis</li>
|
||||
<li>Blixt</li>
|
||||
<li>Breez</li>
|
||||
<li>Blue Wallet</li>
|
||||
<li>Coinos</li>
|
||||
<li>LNBits</li>
|
||||
<li>LNtxtbot</li>
|
||||
</ul>
|
||||
</Col>
|
||||
<Col xs>
|
||||
<ul>
|
||||
<li>Phoenix</li>
|
||||
<li>Simple Bitcoin Wallet</li>
|
||||
<li>Sparrow Wallet</li>
|
||||
<li>ThunderHub</li>
|
||||
<li>Zap Desktop</li>
|
||||
<li>Zeus</li>
|
||||
</ul>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</Col>
|
||||
<Col md className='mx-auto' style={{ maxWidth: '300px' }}>
|
||||
{children}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export function LightningAuth ({ text, callbackUrl }) {
|
||||
// query for challenge
|
||||
const [createAuth, { data, error }] = useMutation(gql`
|
||||
mutation createAuth {
|
||||
|
@ -44,9 +100,9 @@ export function LightningAuth ({ callbackUrl }) {
|
|||
|
||||
if (error) return <div>error</div>
|
||||
|
||||
if (!data) {
|
||||
return <LnQRSkeleton status='generating' />
|
||||
}
|
||||
|
||||
return <LnQRAuth {...data.createAuth} callbackUrl={callbackUrl} />
|
||||
return (
|
||||
<LightningExplainer text={text}>
|
||||
{data ? <LnQRAuth {...data.createAuth} callbackUrl={callbackUrl} /> : <LnQRSkeleton status='generating' />}
|
||||
</LightningExplainer>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
.login {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 3rem;
|
||||
padding-bottom: 3rem;
|
||||
}
|
|
@ -23,7 +23,7 @@ export default function LnQR ({ value, webLn, statusVariant, status }) {
|
|||
|
||||
return (
|
||||
<>
|
||||
<a className='d-block p-3' style={{ background: 'white' }} href={qrValue}>
|
||||
<a className='d-block p-3 mx-auto' style={{ background: 'white', maxWidth: '300px' }} href={qrValue}>
|
||||
<QRCode
|
||||
className='h-auto mw-100' value={qrValue} renderAs='svg' size={300}
|
||||
/>
|
||||
|
|
|
@ -57,56 +57,59 @@ export default function Login ({ providers, callbackUrl, error, text, Header, Fo
|
|||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<LayoutCenter noFooter>
|
||||
<div className={styles.login}>
|
||||
{Header && <Header />}
|
||||
{errorMessage &&
|
||||
<Alert variant='danger' onClose={() => setErrorMessage(undefined)} dismissible>{errorMessage}</Alert>}
|
||||
{router.query.type === 'lightning'
|
||||
? <LightningAuth callbackUrl={callbackUrl} />
|
||||
: (
|
||||
<>
|
||||
<Button
|
||||
className={`mt-2 ${styles.providerButton}`}
|
||||
variant='primary'
|
||||
onClick={() => router.push({
|
||||
pathname: router.pathname,
|
||||
query: { ...router.query, type: 'lightning' }
|
||||
})}
|
||||
>
|
||||
<LightningIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className='mr-3'
|
||||
/>{text || 'Login'} with Lightning
|
||||
</Button>
|
||||
{Object.values(providers).map(provider => {
|
||||
if (provider.name === 'Email' || provider.name === 'Lightning') {
|
||||
return null
|
||||
}
|
||||
const [variant, Icon] =
|
||||
<LayoutCenter>
|
||||
{router.query.type === 'lightning'
|
||||
? <LightningAuth callbackUrl={callbackUrl} text={text} />
|
||||
: (
|
||||
<div className={styles.login}>
|
||||
{Header && <Header />}
|
||||
{errorMessage &&
|
||||
<Alert
|
||||
variant='danger'
|
||||
onClose={() => setErrorMessage(undefined)}
|
||||
dismissible
|
||||
>{errorMessage}
|
||||
</Alert>}
|
||||
<Button
|
||||
className={`mt-2 ${styles.providerButton}`}
|
||||
variant='primary'
|
||||
onClick={() => router.push({
|
||||
pathname: router.pathname,
|
||||
query: { ...router.query, type: 'lightning' }
|
||||
})}
|
||||
>
|
||||
<LightningIcon
|
||||
width={20}
|
||||
height={20}
|
||||
className='mr-3'
|
||||
/>{text || 'Login'} with Lightning
|
||||
</Button>
|
||||
{Object.values(providers).map(provider => {
|
||||
if (provider.name === 'Email' || provider.name === 'Lightning') {
|
||||
return null
|
||||
}
|
||||
const [variant, Icon] =
|
||||
provider.name === 'Twitter'
|
||||
? ['twitter', TwitterIcon]
|
||||
: ['dark', GithubIcon]
|
||||
|
||||
return (
|
||||
<Button
|
||||
className={`mt-2 ${styles.providerButton}`}
|
||||
key={provider.name}
|
||||
variant={variant}
|
||||
onClick={() => signIn(provider.id, { callbackUrl })}
|
||||
>
|
||||
<Icon
|
||||
className='mr-3'
|
||||
/>{text || 'Login'} with {provider.name}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
<div className='mt-2 text-center text-muted font-weight-bold'>or</div>
|
||||
<EmailLoginForm text={text} callbackUrl={callbackUrl} />
|
||||
</>)}
|
||||
{Footer && <Footer />}
|
||||
</div>
|
||||
return (
|
||||
<Button
|
||||
className={`mt-2 ${styles.providerButton}`}
|
||||
key={provider.name}
|
||||
variant={variant}
|
||||
onClick={() => signIn(provider.id, { callbackUrl })}
|
||||
>
|
||||
<Icon
|
||||
className='mr-3'
|
||||
/>{text || 'Login'} with {provider.name}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
<div className='mt-2 text-center text-muted font-weight-bold'>or</div>
|
||||
<EmailLoginForm text={text} callbackUrl={callbackUrl} />
|
||||
{Footer && <Footer />}
|
||||
</div>)}
|
||||
</LayoutCenter>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ $theme-colors: (
|
|||
"twitter" : #1da1f2,
|
||||
"boost" : #8c25f4,
|
||||
"grey" : #e9ecef,
|
||||
"grey-medium" : #d2d2d2,
|
||||
"grey-darkmode": #8c8c8c
|
||||
);
|
||||
|
||||
|
|
|
@ -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 13v7l-8-8 8-8v7h8v2z"/></svg>
|
After Width: | Height: | Size: 162 B |
|
@ -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="M7.828 11H20v2H7.828l5.364 5.364-1.414 1.414L4 12l7.778-7.778 1.414 1.414z"/></svg>
|
After Width: | Height: | Size: 212 B |
Loading…
Reference in New Issue