diff --git a/src/components/Zap.tsx b/src/components/Zap.tsx new file mode 100644 index 0000000..2f441c5 --- /dev/null +++ b/src/components/Zap.tsx @@ -0,0 +1,196 @@ +import { QRCodeSVG } from 'qrcode.react' +import React, { Dispatch, SetStateAction, useMemo } from 'react' +import Countdown, { CountdownRenderProps } from 'react-countdown' +import { toast } from 'react-toastify' +import { ZapController } from '../controllers' +import { useDidMount } from '../hooks' +import '../styles/popup.css' +import { PaymentRequest } from '../types' +import { copyTextToClipboard } from '../utils' + +type PresetAmountProps = { + label: string + value: number + setAmount: Dispatch> +} + +export const PresetAmount = React.memo( + ({ label, value, setAmount }: PresetAmountProps) => { + return ( + + ) + } +) + +type ZapPresetsProps = { + setAmount: Dispatch> +} + +export const ZapPresets = React.memo(({ setAmount }: ZapPresetsProps) => { + return ( + <> + + + + + + ) +}) + +type ZapButtonsProps = { + disabled: boolean + handleGenerateQRCode: () => void + handleSend: () => void +} + +export const ZapButtons = ({ + disabled, + handleGenerateQRCode, + handleSend +}: ZapButtonsProps) => { + return ( +
+ + +
+ ) +} + +type ZapQRProps = { + paymentRequest: PaymentRequest + handleClose: () => void + handleQRExpiry: () => void +} + +export const ZapQR = React.memo( + ({ paymentRequest, handleClose, handleQRExpiry }: ZapQRProps) => { + useDidMount(() => { + ZapController.getInstance() + .pollZapReceipt(paymentRequest) + .then(() => { + toast.success(`Successfully sent sats!`) + }) + .catch((err) => { + toast.error(err.message || err) + }) + .finally(() => { + handleClose() + }) + }) + + const onQrCodeClicked = async () => { + if (!paymentRequest) return + + const zapController = ZapController.getInstance() + + if (await zapController.isWeblnProviderExists()) { + zapController.sendPayment(paymentRequest.pr) + } else { + console.warn('Webln provider not present') + + const href = `lightning:${paymentRequest.pr}` + const a = document.createElement('a') + a.href = href + a.click() + } + } + + return ( +
+ + + +
+ ) + } +) + +const MAX_POLLING_TIME = 2 * 60 * 1000 // 2 minutes in milliseconds + +const renderer = ({ minutes, seconds }: CountdownRenderProps) => ( + + {minutes}:{seconds} + +) + +type TimerProps = { + onTimerExpired: () => void +} + +const Timer = React.memo(({ onTimerExpired }: TimerProps) => { + const expiryTime = useMemo(() => { + return Date.now() + MAX_POLLING_TIME + }, []) + + return ( +
+ + +
+ ) +}) diff --git a/src/layout/header.tsx b/src/layout/header.tsx index 2a4042e..7febe43 100644 --- a/src/layout/header.tsx +++ b/src/layout/header.tsx @@ -2,34 +2,21 @@ import { init as initNostrLogin, launch as launchNostrLoginDialog } from 'nostr-login' -import React, { - Dispatch, - SetStateAction, - useCallback, - useEffect, - useMemo, - useState -} from 'react' +import React, { useCallback, useEffect, useState } from 'react' import { Link } from 'react-router-dom' +import { toast } from 'react-toastify' import { Banner } from '../components/Banner' +import { LoadingSpinner } from '../components/LoadingSpinner' +import { ZapButtons, ZapPresets, ZapQR } from '../components/Zap' import { MetadataController, ZapController } from '../controllers' -import { useAppDispatch, useAppSelector, useDidMount } from '../hooks' +import { useAppDispatch, useAppSelector } from '../hooks' import { appRoutes } from '../routes' import { setIsAuth, setUser } from '../store/reducers/user' import mainStyles from '../styles//main.module.scss' import navStyles from '../styles/nav.module.scss' import '../styles/popup.css' -import { - copyTextToClipboard, - formatNumber, - npubToHex, - unformatNumber -} from '../utils' -import { toast } from 'react-toastify' import { PaymentRequest } from '../types' -import { LoadingSpinner } from '../components/LoadingSpinner' -import { QRCodeSVG } from 'qrcode.react' -import Countdown, { CountdownRenderProps } from 'react-countdown' +import { formatNumber, npubToHex, unformatNumber } from '../utils' export const Header = () => { const dispatch = useAppDispatch() @@ -395,26 +382,7 @@ const TipButtonWithDialog = React.memo(() => { />
- - - - +
@@ -428,41 +396,11 @@ const TipButtonWithDialog = React.memo(() => { onChange={(e) => setMessage(e.target.value)} />
-
- - -
+ {paymentRequest && ( { ) }) - -type PresetAmountProps = { - label: string - value: number - setAmount: Dispatch> -} - -const PresetAmount = React.memo( - ({ label, value, setAmount }: PresetAmountProps) => { - return ( - - ) - } -) - -type ZapQRProps = { - paymentRequest: PaymentRequest - handleClose: () => void - handleQRExpiry: () => void -} - -const ZapQR = React.memo( - ({ paymentRequest, handleClose, handleQRExpiry }: ZapQRProps) => { - useDidMount(() => { - ZapController.getInstance() - .pollZapReceipt(paymentRequest) - .then(() => { - toast.success(`Successfully sent sats!`) - }) - .catch((err) => { - toast.error(err.message || err) - }) - .finally(() => { - handleClose() - }) - }) - - const onQrCodeClicked = async () => { - if (!paymentRequest) return - - const zapController = ZapController.getInstance() - - if (await zapController.isWeblnProviderExists()) { - zapController.sendPayment(paymentRequest.pr) - } else { - console.warn('Webln provider not present') - - const href = `lightning:${paymentRequest.pr}` - const a = document.createElement('a') - a.href = href - a.click() - } - } - - return ( -
- - - -
- ) - } -) - -const MAX_POLLING_TIME = 2 * 60 * 1000 // 2 minutes in milliseconds - -const renderer = ({ minutes, seconds }: CountdownRenderProps) => ( - - {minutes}:{seconds} - -) - -type TimerProps = { - onTimerExpired: () => void -} - -const Timer = React.memo(({ onTimerExpired }: TimerProps) => { - const expiryTime = useMemo(() => { - return Date.now() + MAX_POLLING_TIME - }, []) - - return ( -
- - -
- ) -})