/* global alert */ import React from 'react'; import { Text, Dimensions, ActivityIndicator, View, TouchableOpacity, TouchableWithoutFeedback, TextInput, Keyboard } from 'react-native'; import { Icon } from 'react-native-elements'; import PropTypes from 'prop-types'; import { BlueSpacing20, BlueButton, SafeBlueArea, BlueCard, BlueHeaderDefaultSub } from '../../BlueComponents'; /** @type {AppStorage} */ let BlueApp = require('../../BlueApp'); let currency = require('../../currency'); let EV = require('../../events'); let loc = require('../../loc'); const { width } = Dimensions.get('window'); export default class ScanLndInvoice extends React.Component { static navigationOptions = { header: ({ navigation }) => { return navigation.goBack(null)} />; }, }; state = { isLoading: false, }; constructor(props) { super(props); let fromSecret; if (props.navigation.state.params.fromSecret) fromSecret = props.navigation.state.params.fromSecret; let fromWallet = {}; for (let w of BlueApp.getWallets()) { if (w.getSecret() === fromSecret) { fromWallet = w; break; } } this.state = { fromWallet, fromSecret, }; } async componentDidMount() { EV( EV.enum.CREATE_TRANSACTION_NEW_DESTINATION_ADDRESS, data => { this.processInvoice(data); }, true, ); } async processInvoice(data) { if (this.ignoreRead) return; this.ignoreRead = true; setTimeout(() => { this.ignoreRead = false; }, 6000); if (!this.state.fromWallet) { alert('Error: cant find source wallet (this should never happen)'); return this.props.navigation.goBack(); } data = data.replace('LIGHTNING:', '').replace('lightning:', ''); console.log(data); /** * @type {LightningCustodianWallet} */ let w = this.state.fromWallet; let decoded = false; try { decoded = await w.decodeInvoice(data); let expiresIn = (decoded.timestamp * 1 + decoded.expiry * 1) * 1000; // ms if (+new Date() > expiresIn) { expiresIn = 'expired'; } else { expiresIn = Math.round((expiresIn - +new Date()) / (60 * 1000)) + ' min'; } Keyboard.dismiss(); this.setState({ isPaying: true, invoice: data, decoded, expiresIn, }); } catch (Err) { alert(Err.message); } } async pay() { if (!this.state.hasOwnProperty('decoded')) { return null; } let decoded = this.state.decoded; /** @type {LightningCustodianWallet} */ let fromWallet = this.state.fromWallet; let expiresIn = (decoded.timestamp * 1 + decoded.expiry * 1) * 1000; // ms if (+new Date() > expiresIn) { return alert('Invoice expired'); } this.setState({ isPayingInProgress: true, }); let start = +new Date(); let end; try { await fromWallet.payInvoice(this.state.invoice); end = +new Date(); } catch (Err) { console.log(Err.message); this.props.navigation.goBack(); return alert('Error'); } console.log('payInvoice took', (end - start) / 1000, 'sec'); EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // someone should fetch txs alert('Success'); this.props.navigation.goBack(); } render() { return ( {this.state.hasOwnProperty('decoded') && this.state.decoded !== undefined && currency.satoshiToLocalCurrency(this.state.decoded.num_satoshis)} {this.state.hasOwnProperty('decoded') && this.state.decoded !== undefined && currency.satoshiToBTC(this.state.decoded.num_satoshis)} { if (text.toLowerCase().startsWith('lnb') || text.toLowerCase().startsWith('lntb')) { this.processInvoice(text); } else { this.setState({ decoded: undefined, expiresIn: undefined }); } }} placeholder={loc.wallets.details.destination} numberOfLines={1} value={this.state.hasOwnProperty('decoded') && this.state.decoded !== undefined ? this.state.decoded.destination : ''} style={{ flex: 1, marginHorizontal: 8, minHeight: 33, height: 33 }} editable={!this.state.isLoading} /> this.props.navigation.navigate('ScanQrAddress')} style={{ width: 75, height: 36, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', backgroundColor: '#bebebe', borderRadius: 4, paddingVertical: 4, paddingHorizontal: 8, marginHorizontal: 4, }} > {loc.send.details.scan} {}} placeholder={loc.wallets.details.description} numberOfLines={1} value={this.state.hasOwnProperty('decoded') && this.state.decoded !== undefined ? this.state.decoded.description : ''} style={{ flex: 1, marginHorizontal: 8, minHeight: 33, height: 33 }} editable={!this.state.isLoading} /> {this.state.expiresIn !== undefined && ( Expires in: {this.state.expiresIn} )} {this.state.hasOwnProperty('decoded') && this.state.decoded !== undefined && (() => { if (this.state.isPayingInProgress) { return ( ); } else { return ( { this.pay(); }} /> ); } })()} ); } } ScanLndInvoice.propTypes = { navigation: PropTypes.shape({ goBack: PropTypes.function, navigate: PropTypes.function, state: PropTypes.shape({ params: PropTypes.shape({ fromSecret: PropTypes.string, }), }), }), };