BlueWallet/screen/lnd/lndViewInvoice.js

299 lines
11 KiB
JavaScript
Raw Normal View History

2018-12-25 17:34:51 +01:00
import React, { Component } from 'react';
2019-08-06 06:20:33 +02:00
import { View, Dimensions, ScrollView, BackHandler, InteractionManager } from 'react-native';
import Share from 'react-native-share';
import {
BlueLoading,
BlueText,
SafeBlueArea,
BlueButton,
BlueCopyTextToClipboard,
BlueNavigationStyle,
BlueSpacing20,
} from '../../BlueComponents';
2018-12-25 17:34:51 +01:00
import PropTypes from 'prop-types';
import ReactNativeHapticFeedback from 'react-native-haptic-feedback';
import { Icon } from 'react-native-elements';
2019-02-14 06:15:56 +01:00
import QRCode from 'react-native-qrcode-svg';
2018-12-25 17:34:51 +01:00
/** @type {AppStorage} */
let BlueApp = require('../../BlueApp');
const loc = require('../../loc');
const EV = require('../../events');
2019-01-05 02:28:08 +01:00
const { width, height } = Dimensions.get('window');
2018-12-25 17:34:51 +01:00
export default class LNDViewInvoice extends Component {
static navigationOptions = ({ navigation }) =>
navigation.getParam('isModal') === true
? {
...BlueNavigationStyle(navigation, true, () => navigation.dismiss()),
title: 'Lightning Invoice',
headerLeft: null,
}
: { ...BlueNavigationStyle(), title: 'Lightning Invoice' };
2018-12-25 17:34:51 +01:00
constructor(props) {
super(props);
const invoice = props.navigation.getParam('invoice');
const fromWallet = props.navigation.getParam('fromWallet');
2018-12-25 17:34:51 +01:00
this.state = {
invoice,
fromWallet,
isLoading: typeof invoice === 'string',
addressText: typeof invoice === 'object' && invoice.hasOwnProperty('payment_request') ? invoice.payment_request : invoice,
isFetchingInvoices: true,
qrCodeHeight: height > width ? width - 20 : width / 2,
2018-12-25 17:34:51 +01:00
};
this.fetchInvoiceInterval = undefined;
2019-08-30 06:14:06 +02:00
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
async componentDidMount() {
this.fetchInvoiceInterval = setInterval(async () => {
if (this.state.isFetchingInvoices) {
try {
const userInvoices = await this.state.fromWallet.getUserInvoices(20);
// fetching only last 20 invoices
// for invoice that was created just now - that should be enough (it is basically the last one, so limit=1 would be sufficient)
// but that might not work as intended IF user creates 21 invoices, and then tries to check the status of invoice #0, it just wont be updated
const updatedUserInvoice = userInvoices.filter(invoice =>
typeof this.state.invoice === 'object'
? invoice.payment_request === this.state.invoice.payment_request
: invoice.payment_request === this.state.invoice,
)[0];
if (typeof updatedUserInvoice !== 'undefined') {
this.setState({ invoice: updatedUserInvoice, isLoading: false, addressText: updatedUserInvoice.payment_request });
if (updatedUserInvoice.ispaid) {
// we fetched the invoice, and it is paid :-)
this.setState({ isFetchingInvoices: false });
2019-05-03 14:36:11 +02:00
ReactNativeHapticFeedback.trigger('notificationSuccess', { ignoreAndroidSystemSettings: false });
clearInterval(this.fetchInvoiceInterval);
this.fetchInvoiceInterval = undefined;
EV(EV.enum.REMOTE_TRANSACTIONS_COUNT_CHANGED); // remote because we want to refetch from server tx list and balance
} else {
const currentDate = new Date();
const now = (currentDate.getTime() / 1000) | 0;
const invoiceExpiration = updatedUserInvoice.timestamp + updatedUserInvoice.expire_time;
if (invoiceExpiration < now && !updatedUserInvoice.ispaid) {
// invoice expired :-(
this.setState({ isFetchingInvoices: false });
2019-05-03 14:36:11 +02:00
ReactNativeHapticFeedback.trigger('notificationError', { ignoreAndroidSystemSettings: false });
clearInterval(this.fetchInvoiceInterval);
this.fetchInvoiceInterval = undefined;
EV(EV.enum.TRANSACTIONS_COUNT_CHANGED);
}
}
}
} catch (error) {
console.log(error);
}
}
2019-01-01 01:09:10 +01:00
}, 3000);
}
async componentWillUnmount() {
clearInterval(this.fetchInvoiceInterval);
this.fetchInvoiceInterval = undefined;
2019-08-30 06:14:06 +02:00
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
2019-01-12 00:01:52 +01:00
}
2019-08-30 06:14:06 +02:00
handleBackButton = () => {
this.props.navigation.goBack(null);
2019-01-12 00:01:52 +01:00
return true;
2019-08-30 06:14:06 +02:00
};
2018-12-25 17:34:51 +01:00
2019-01-05 02:28:08 +01:00
onLayout = () => {
const { height } = Dimensions.get('window');
this.setState({ qrCodeHeight: height > width ? width - 20 : width / 2 });
2019-01-05 02:28:08 +01:00
};
2018-12-25 17:34:51 +01:00
render() {
if (this.state.isLoading) {
return <BlueLoading />;
}
const { invoice } = this.state;
if (typeof invoice === 'object') {
const currentDate = new Date();
const now = (currentDate.getTime() / 1000) | 0;
const invoiceExpiration = invoice.timestamp + invoice.expire_time;
2019-05-04 00:24:17 +02:00
if (this.state.showPreimageQr) {
return (
<SafeBlueArea style={{ flex: 1 }}>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<BlueText>Preimage:</BlueText>
<BlueSpacing20 />
<QRCode
value={(invoice.payment_preimage && typeof invoice.payment_preimage === 'string' && invoice.payment_preimage) || 'none'}
logo={require('../../img/qr-code.png')}
size={this.state.qrCodeHeight}
logoSize={90}
2019-08-06 06:20:33 +02:00
getRef={c => (this.qrCodeSVG = c)}
2019-05-04 00:24:17 +02:00
color={BlueApp.settings.foregroundColor}
logoBackgroundColor={BlueApp.settings.brandingColor}
/>
<BlueSpacing20 />
2019-08-11 04:37:52 +02:00
<BlueCopyTextToClipboard text={invoice.payment_preimage} />
2019-05-04 00:24:17 +02:00
</View>
</SafeBlueArea>
);
}
if (invoice.ispaid || invoice.type === 'paid_invoice') {
return (
<SafeBlueArea style={{ flex: 1 }}>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<View
style={{
backgroundColor: '#ccddf9',
width: 120,
height: 120,
borderRadius: 60,
alignSelf: 'center',
justifyContent: 'center',
2019-09-18 00:27:24 +02:00
marginTop: -100,
marginBottom: 30,
}}
>
<Icon name="check" size={50} type="font-awesome" color="#0f5cc0" />
</View>
2019-05-04 00:58:23 +02:00
<BlueText>{loc.lndViewInvoice.has_been_paid}</BlueText>
2019-05-04 00:24:17 +02:00
{invoice.payment_preimage && typeof invoice.payment_preimage === 'string' && (
<View style={{ position: 'absolute', bottom: 0 }}>
<BlueButton
backgroundColor="#FFFFFF"
icon={{
name: 'info',
type: 'entypo',
color: BlueApp.settings.buttonTextColor,
}}
onPress={() => this.setState({ showPreimageQr: true })}
title=" "
/>
</View>
)}
</View>
</SafeBlueArea>
);
}
if (invoiceExpiration < now && !invoice.ispaid) {
return (
<SafeBlueArea style={{ flex: 1 }}>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<View
style={{
backgroundColor: '#ccddf9',
width: 120,
height: 120,
borderRadius: 60,
alignSelf: 'center',
justifyContent: 'center',
2019-09-18 00:27:24 +02:00
marginTop: -100,
marginBottom: 30,
}}
>
<Icon name="times" size={50} type="font-awesome" color="#0f5cc0" />
</View>
2019-05-04 00:58:23 +02:00
<BlueText>{loc.lndViewInvoice.wasnt_paid_and_expired}</BlueText>
</View>
</SafeBlueArea>
);
} else if (invoiceExpiration > now && invoice.ispaid) {
if (invoice.ispaid) {
return (
<SafeBlueArea style={{ flex: 1 }}>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
2019-05-04 00:58:23 +02:00
<BlueText>{loc.lndViewInvoice.has_been_paid}</BlueText>
</View>
</SafeBlueArea>
);
}
}
}
// Invoice has not expired, nor has it been paid for.
2018-12-25 17:34:51 +01:00
return (
<SafeBlueArea>
<ScrollView>
<View
style={{
flex: 1,
alignItems: 'center',
marginTop: 8,
justifyContent: 'space-between',
}}
onLayout={this.onLayout}
>
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 16 }}>
2019-02-14 06:15:56 +01:00
<QRCode
value={typeof this.state.invoice === 'object' ? invoice.payment_request : invoice}
2019-02-14 06:15:56 +01:00
logo={require('../../img/qr-code.png')}
size={this.state.qrCodeHeight}
2019-02-14 06:15:56 +01:00
logoSize={90}
2019-08-06 06:20:33 +02:00
getRef={c => (this.qrCodeSVG = c)}
2019-02-14 06:15:56 +01:00
color={BlueApp.settings.foregroundColor}
logoBackgroundColor={BlueApp.settings.brandingColor}
/>
</View>
<BlueSpacing20 />
2019-05-04 00:58:23 +02:00
{invoice && invoice.amt && (
<BlueText>
{loc.lndViewInvoice.please_pay} {invoice.amt} {loc.lndViewInvoice.sats}
</BlueText>
)}
{invoice && invoice.hasOwnProperty('description') && invoice.description.length > 0 && (
2019-05-04 00:58:23 +02:00
<BlueText>
{loc.lndViewInvoice.for} {invoice.description}
</BlueText>
)}
<BlueCopyTextToClipboard text={this.state.invoice.payment_request} />
<BlueButton
icon={{
name: 'share-alternative',
type: 'entypo',
size: 10,
color: BlueApp.settings.buttonTextColor,
}}
onPress={async () => {
2019-08-06 06:20:33 +02:00
if (this.qrCodeSVG === undefined) {
Share.open({ message: `lightning:${invoice.payment_request}` }).catch(error => console.log(error));
} else {
InteractionManager.runAfterInteractions(async () => {
this.qrCodeSVG.toDataURL(data => {
let shareImageBase64 = {
message: `lightning:${invoice.payment_request}`,
url: `data:image/png;base64,${data}`,
};
Share.open(shareImageBase64).catch(error => console.log(error));
});
});
}
}}
title={loc.receive.details.share}
/>
<BlueSpacing20 />
2019-05-22 14:09:00 +02:00
<BlueButton
style={{
backgroundColor: BlueApp.settings.brandingColor,
}}
onPress={() => this.props.navigation.navigate('LNDViewAdditionalInvoiceInformation', { fromWallet: this.state.fromWallet })}
2019-05-04 00:58:23 +02:00
title={loc.lndViewInvoice.additional_info}
/>
2018-12-25 17:34:51 +01:00
</View>
<BlueSpacing20 />
</ScrollView>
2018-12-25 17:34:51 +01:00
</SafeBlueArea>
);
}
}
LNDViewInvoice.propTypes = {
navigation: PropTypes.shape({
goBack: PropTypes.func,
navigate: PropTypes.func,
getParam: PropTypes.func,
popToTop: PropTypes.func,
2018-12-25 17:34:51 +01:00
}),
};