import { useCallback, useMemo } from 'react' import { InputGroup, Nav } from 'react-bootstrap' import classNames from 'classnames' import styles from '@/styles/wallet.module.css' import navStyles from '@/styles/nav.module.css' import { Checkbox, Form, Input, PasswordInput, SubmitButton } from '@/components/form' import CancelButton from '@/components/cancel-button' import Text from '@/components/text' import Info from '@/components/info' import { useFormState, useMaxSteps, useNext, useStepIndex } from '@/components/multi-step-form' import { isTemplate, isWallet, protocolDisplayName, protocolFormId, protocolLogName, walletGuideUrl, walletLud16Domain } from '@/wallets/lib/util' import { WalletLayout, WalletLayoutHeader, WalletLayoutImageOrName, WalletLogs } from '@/wallets/client/components' import { TemplateLogsProvider, useTestSendPayment, useWalletLogger, useTestCreateInvoice, useWalletSupport } from '@/wallets/client/hooks' import ArrowRight from '@/svgs/arrow-right-s-fill.svg' import InfoIcon from '@/svgs/information-fill.svg' import Link from 'next/link' import { useFormikContext } from 'formik' import { WalletMultiStepFormContextProvider, Step, useWallet, useWalletProtocols, useProtocol, useProtocolForm } from './hooks' import { Settings } from './settings' import { BackButton, SkipButton } from './button' export function WalletMultiStepForm ({ wallet }) { const initial = useMemo(() => wallet.protocols .filter(p => !isTemplate(p)) .reduce((acc, p) => { const formId = protocolFormId(p) return { ...acc, [formId]: p } }, {}), [wallet]) const support = useWalletSupport(wallet) const steps = useMemo(() => [ support.send && Step.SEND, support.receive && Step.RECEIVE, Step.SETTINGS ].filter(Boolean), [support]) const guideUrl = walletGuideUrl(wallet.name) return (
{guideUrl && ( guide )} {steps.map(step => { // WalletForm is aware of the current step via hooks // and can thus render a different form for send vs. receive if (step === Step.SEND) return if (step === Step.RECEIVE) return return })}
) } function WalletForm () { return ( ) } function WalletProtocolSelector () { const protocols = useWalletProtocols() const [protocol, selectProtocol] = useProtocol() return ( ) } function WalletProtocolForm () { const wallet = useWallet() const [protocol] = useProtocol() const next = useNext() const testSendPayment = useTestSendPayment(protocol) const testCreateInvoice = useTestCreateInvoice(protocol) const logger = useWalletLogger(protocol) const [{ fields, initial, schema }, setFormState] = useProtocolForm(protocol) // create a copy of values to avoid mutating the original const onSubmit = useCallback(async ({ ...values }) => { const lud16Domain = walletLud16Domain(wallet.name) if (values.address && lud16Domain) { values.address = `${values.address}@${lud16Domain}` } const name = protocolLogName(protocol) if (isTemplate(protocol)) { values.enabled = true } if (values.enabled) { try { if (protocol.send) { logger.info(`testing ${name} send ...`) const additionalValues = await testSendPayment(values) values = { ...values, ...additionalValues } logger.ok(`${name} send ok`) } else { logger.info(`testing ${name} receive ...`) await testCreateInvoice(values) logger.ok(`${name} receive ok`) } } catch (err) { logger.error(err.message) throw err } } setFormState(values) next() }, [protocol, wallet, setFormState, testSendPayment, logger, next]) return ( <>
{fields.map(field => )} {!isTemplate(protocol) && } ) } function WalletProtocolFormNavigator () { const wallet = useWallet() const stepIndex = useStepIndex() const maxSteps = useMaxSteps() const [formState] = useFormState() // was something already configured or was something configured just now? const configExists = (isWallet(wallet) && wallet.protocols.length > 0) || Object.keys(formState).length > 0 // don't allow going to settings as last step with nothing configured const hideSkip = stepIndex === maxSteps - 2 && !configExists return (
{stepIndex === 0 ? cancel : } {!hideSkip ? :
} next
) } function WalletProtocolFormField ({ type, ...props }) { const wallet = useWallet() const [protocol] = useProtocol() const formik = useFormikContext() function transform ({ validate, encrypt, editable, help, share, ...props }) { const [upperHint, bottomHint] = Array.isArray(props.hint) ? props.hint : [null, props.hint] const parseHelpText = text => Array.isArray(text) ? text.join('\n\n') : text const _help = help ? ( typeof help === 'string' ? { label: null, text: help } : ( Array.isArray(help) ? { label: null, text: parseHelpText(help) } : { label: help.label, text: parseHelpText(help.text) } ) ) : null const readOnly = !!protocol.config?.[props.name] && editable === false const label = (
{props.label} {_help && ( {_help.text} )} {upperHint ? {upperHint} : (!props.required ? 'optional' : null)}
) let append, onPaste const lud16Domain = walletLud16Domain(wallet.name) if (props.name === 'address' && lud16Domain) { append = @{lud16Domain} onPaste = (e) => { e.preventDefault() const value = (e.clipboardData || window.clipboardData).getData('text') formik.setFieldValue( props.name, value.endsWith(`@${lud16Domain}`) ? value.slice(0, -`@${lud16Domain}`.length) : value ) } } return { ...props, hint: bottomHint, label, readOnly, append, onPaste } } switch (type) { case 'text': { return } case 'password': return default: return null } }