Skip to content

Instantly share code, notes, and snippets.

@john-zaprite
Created March 13, 2022 19:29
Show Gist options
  • Save john-zaprite/a4f7a18ee3b191853e6af2358bc9c787 to your computer and use it in GitHub Desktop.
Save john-zaprite/a4f7a18ee3b191853e6af2358bc9c787 to your computer and use it in GitHub Desktop.
import {
Box,
Button,
Heading,
HStack,
Image,
Input,
Spinner,
Stack,
Text,
useColorModeValue as mode,
} from '@chakra-ui/react'
import Link from 'next/link'
import QRCode from 'qrcode'
import { useEffect, useState } from 'react'
import { FaQrcode } from 'react-icons/fa'
import AppMain from '../layouts/AppMain'
import useSWR from 'swr'
import ClipboardCopyIcon from '../hooks/useClipboard copy'
import { useRouter } from 'next/router'
const Login = () => {
// ----------------
// STATE
// ----------------
const [isLoading, setIsLoading] = useState(false)
const [isGeneratingQr, setIsGeneratingQr] = useState(false)
const [isAuthenticating, setIsAuthenticating] = useState(false)
const [qrPng, setQrPng] = useState(null)
const [paymentLink, setPaymentLink] = useState(null)
const [challenge, setChallenge] = useState(null)
// ----------------
// HANDLERS
// ----------------
const handleLNurlAuthLogin = async () => {
setIsLoading(true)
try {
const { success, data } = await (
await fetch('/api/auth/get-lnurl-auth', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
).json()
if (success) {
const lnurl = data.lnurl
const challenge = data.challenge
generateQRCode(lnurl)
setPaymentLink(lnurl)
setChallenge(challenge)
setIsAuthenticating(true)
}
} catch {
console.error('LN-URL auth error.')
} finally {
setIsLoading(false)
}
}
const generateQRCode = async (string) => {
const qrUrl = `lightning:${string}`
setIsGeneratingQr(true)
const opts = {
errorCorrectionLevel: 'H',
type: 'image/webp',
quality: 0.75,
color: {
dark: '#0e0910',
light: '#ffffff',
},
}
try {
const dataImg = await QRCode.toDataURL(string, opts).then(
(dataImg) => setQrPng(dataImg)
)
} catch (error) {
console.error('QR Code did not generate.', error)
} finally {
setIsGeneratingQr(false)
}
}
return (
<AppMain>
<Stack
sx={{
m: 'auto',
width: '80vw',
maxW: '24em',
spacing: '8',
}}>
<Stack
sx={{
spacing: '6',
align: 'center',
}}>
<Heading
// size={useBreakpointValue({ base: 'xs', md: 'sm' })}
>
Log in to your account
</Heading>
</Stack>
<Stack
sx={{
p: 6,
spacing: '6',
borderRadius: 2,
bg: mode('#ffffff', 'gray.700'),
}}>
<Box sx={{ width: '100%', aspectRatio: '1' }}>
{isGeneratingQr && <Spinner />}
{!isAuthenticating && (
<Image
src={'/images/lnurl_placeholder@2x.png'}
alt={''}
width={'100%'}
/>
)}
{isAuthenticating && qrPng && (
<Authenticate
challenge={challenge}
paymentLink={paymentLink}
qrPng={qrPng}
/>
)}
</Box>
<Button
isLoading={isLoading}
loadingText={'Authenticating...'}
rightIcon={<FaQrcode />}
colorScheme='primary'
sx={{ minWidth: '10em' }}
onClick={handleLNurlAuthLogin}
disabled={isAuthenticating}>
Authenticate
</Button>
</Stack>
<Box>
<Text>
Some info? Link to list of supported wallets? Icons?
</Text>
</Box>
</Stack>
</AppMain>
)
}
export default Login
const Authenticate = ({ challenge, paymentLink, qrPng }) => {
const router = useRouter()
// ----------------
// DATA
// ----------------
const { data, error } = useSWR(
`/api/auth/check-challenge/?challenge=${challenge}`,
(url) => fetch(url).then((res) => res.json()),
{ refreshInterval: 5000, shouldRetryOnError: false }
)
if (error) console.error('Challenge failed.', error)
// ----------------
// EFFECTS
// ----------------
useEffect(() => {
if (data) {
const response = data.data
if (data) {
// const status = response?.status || null
const sessionId = response?.data?.session_key || null
const userId = response?.data?.user_id || null
const date = new Date(response?.data?.timestamp) || new Date()
const expireMs = 14 * 24 * 60 * 60 * 1000
date.setTime(date.getTime() + expireMs)
localStorage.setItem('user_id', userId)
document.cookie = `SESSION_ID=${sessionId}; expires=${date.toUTCString()}; SameSite=Strict; path=/`
if (userId && sessionId) {
router.push('/dashboard')
}
// TODO
// run function that creates a user (?)
}
}
}, [data])
return (
<Box>
<Link href={`lightning:${paymentLink}`} passHref>
<a>
<Image src={qrPng} alt='ln-url auth' />
</a>
</Link>
<HStack mt={2} spacing='4'>
<Input
placeholder={'LN-URL auth ...'}
value={paymentLink}
readOnly
isTruncated
/>
<ClipboardCopyIcon value={paymentLink} />
</HStack>
</Box>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment