import React, { useState, useEffect, useContext } from 'react';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { I18nManager, Image, ScrollView, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { useNavigation, useRoute, useTheme } from '@react-navigation/native';
import { Icon } from 'react-native-elements';
import {
BlueButton,
BlueCard,
BlueDismissKeyboardInputAccessory,
BlueLoading,
BlueSpacing20,
BlueText,
SafeBlueArea,
} from '../../BlueComponents';
import navigationStyle from '../../components/navigationStyle';
import AmountInput from '../../components/AmountInput';
import Lnurl from '../../class/lnurl';
import { BitcoinUnit, Chain } from '../../models/bitcoinUnits';
import loc, { formatBalanceWithoutSuffix, formatBalance } from '../../loc';
import Biometric from '../../class/biometrics';
import { BlueStorageContext } from '../../blue_modules/storage-context';
import alert from '../../components/Alert';
const prompt = require('../../helpers/prompt');
const currency = require('../../blue_modules/currency');
const LnurlPay = () => {
const { wallets } = useContext(BlueStorageContext);
const { walletID, lnurl } = useRoute().params;
const wallet = wallets.find(w => w.getID() === walletID);
const [unit, setUnit] = useState(wallet.getPreferredBalanceUnit());
const [isLoading, setIsLoading] = useState(true);
const [LN, setLN] = useState();
const [payButtonDisabled, setPayButtonDisabled] = useState(true);
const [payload, setPayload] = useState();
const { setParams, pop, navigate } = useNavigation();
const [amount, setAmount] = useState();
const { colors } = useTheme();
const stylesHook = StyleSheet.create({
root: {
backgroundColor: colors.background,
},
walletWrapLabel: {
color: colors.buttonAlternativeTextColor,
},
walletWrapBalance: {
color: colors.buttonAlternativeTextColor,
},
walletWrapSats: {
color: colors.buttonAlternativeTextColor,
},
});
useEffect(() => {
if (lnurl) {
const ln = new Lnurl(lnurl, AsyncStorage);
ln.callLnurlPayService()
.then(setPayload)
.catch(error => {
alert(error.message);
pop();
});
setLN(ln);
setIsLoading(false);
}
}, [lnurl, pop]);
useEffect(() => {
setPayButtonDisabled(isLoading);
}, [isLoading]);
useEffect(() => {
if (payload) {
let newAmount = payload.min;
switch (unit) {
case BitcoinUnit.BTC:
newAmount = currency.satoshiToBTC(newAmount);
break;
case BitcoinUnit.LOCAL_CURRENCY:
newAmount = currency.satoshiToLocalCurrency(newAmount, false);
break;
}
setAmount(newAmount);
}
}, [payload]); // eslint-disable-line react-hooks/exhaustive-deps
const onWalletSelect = wallet => {
setParams({ walletID: wallet.getID() });
pop();
};
const pay = async () => {
setPayButtonDisabled(true);
/** @type {Lnurl} */
const isBiometricsEnabled = await Biometric.isBiometricUseCapableAndEnabled();
if (isBiometricsEnabled) {
if (!(await Biometric.unlockWithBiometrics())) {
return;
}
}
let amountSats = amount;
switch (unit) {
case BitcoinUnit.SATS:
amountSats = parseInt(amountSats); // nop
break;
case BitcoinUnit.BTC:
amountSats = currency.btcToSatoshi(amountSats);
break;
case BitcoinUnit.LOCAL_CURRENCY:
amountSats = currency.btcToSatoshi(currency.fiatToBTC(amountSats));
break;
}
/** @type {LightningCustodianWallet} */
let bolt11payload;
try {
let comment;
if (LN.getCommentAllowed()) {
comment = await prompt('Comment', '', false, 'plain-text');
}
bolt11payload = await LN.requestBolt11FromLnurlPayService(amountSats, comment);
await wallet.payInvoice(bolt11payload.pr);
const decoded = wallet.decodeInvoice(bolt11payload.pr);
setPayButtonDisabled(false);
// success, probably
ReactNativeHapticFeedback.trigger('notificationSuccess', { ignoreAndroidSystemSettings: false });
if (wallet.last_paid_invoice_result && wallet.last_paid_invoice_result.payment_preimage) {
await LN.storeSuccess(decoded.payment_hash, wallet.last_paid_invoice_result.payment_preimage);
}
navigate('ScanLndInvoiceRoot', {
screen: 'LnurlPaySuccess',
params: {
paymentHash: decoded.payment_hash,
justPaid: true,
fromWalletID: walletID,
},
});
setIsLoading(false);
} catch (Err) {
console.log(Err.message);
setIsLoading(false);
setPayButtonDisabled(false);
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
return alert(Err.message);
}
};
const renderWalletSelectionButton = (
{!isLoading && (
navigate('SelectWallet', { onWalletSelect, chainType: Chain.OFFCHAIN })}
>
{loc.wallets.select_wallet.toLowerCase()}
)}
navigate('SelectWallet', { onWalletSelect, chainType: Chain.OFFCHAIN })}
>
{wallet.getLabel()}
{formatBalanceWithoutSuffix(wallet.getBalance(), BitcoinUnit.SATS, false)}
{BitcoinUnit.SATS}
);
const renderGotPayload = () => {
return (
{loc.formatString(loc.lndViewInvoice.please_pay_between_and, {
min: formatBalance(payload?.min, unit),
max: formatBalance(payload?.max, unit),
})}
{payload?.image && (
<>
>
)}
{payload?.description}
{payload?.domain}
{payButtonDisabled ? : }
{renderWalletSelectionButton}
);
};
return isLoading || wallet === undefined || amount === undefined ? (
) : (
renderGotPayload()
);
};
export default LnurlPay;
const styles = StyleSheet.create({
img: { width: 200, height: 200, alignSelf: 'center' },
alignSelfCenter: {
alignSelf: 'center',
},
root: {
flex: 1,
justifyContent: 'center',
},
walletSelectRoot: {
alignItems: 'center',
justifyContent: 'flex-end',
},
walletSelectTouch: {
flexDirection: 'row',
alignItems: 'center',
},
walletSelectText: {
color: '#9aa0aa',
fontSize: 14,
marginRight: 8,
},
walletWrap: {
flexDirection: 'row',
alignItems: 'center',
marginVertical: 4,
},
walletWrapTouch: {
flexDirection: 'row',
alignItems: 'center',
},
walletWrapLabel: {
fontSize: 14,
},
walletWrapBalance: {
fontSize: 14,
fontWeight: '600',
marginLeft: 4,
marginRight: 4,
},
walletWrapSats: {
fontSize: 11,
fontWeight: '600',
textAlignVertical: 'bottom',
marginTop: 2,
},
});
LnurlPay.navigationOptions = navigationStyle({
title: '',
closeButton: true,
closeButtonFunc: ({ navigation }) => navigation.dangerouslyGetParent().popToTop(),
});