Files
app.zeusln.zeus/views/Transaction.tsx
T

434 lines
17 KiB
TypeScript

import * as React from 'react';
import forEach from 'lodash/forEach';
import isNull from 'lodash/isNull';
import {
StyleSheet,
ScrollView,
Text,
TouchableOpacity,
View
} from 'react-native';
import { inject, observer } from 'mobx-react';
import { Route } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import { Row } from '../components/layout/Row';
import Amount from '../components/Amount';
import Button from '../components/Button';
import Header from '../components/Header';
import KeyValue from '../components/KeyValue';
import Screen from '../components/Screen';
import BackendUtils from '../utils/BackendUtils';
import PrivacyUtils from '../utils/PrivacyUtils';
import Transaction from '../models/Transaction';
import UrlUtils from '../utils/UrlUtils';
import NodeInfoStore from '../stores/NodeInfoStore';
import TransactionsStore from '../stores/TransactionsStore';
import { localeString } from '../utils/LocaleUtils';
import { themeColor } from '../utils/ThemeUtils';
import CaretRight from '../assets/images/SVG/Caret Right.svg';
import EditNotes from '../assets/images/SVG/Pen.svg';
interface TransactionProps {
navigation: StackNavigationProp<any, any>;
NodeInfoStore: NodeInfoStore;
TransactionsStore: TransactionsStore;
route: Route<'Transaction', { transaction: Transaction }>;
}
interface TransactionState {
storedNote: string;
}
@inject('NodeInfoStore', 'TransactionsStore')
@observer
export default class TransactionView extends React.Component<
TransactionProps,
TransactionState
> {
state = {
storedNote: ''
};
async componentDidMount() {
const { navigation, route } = this.props;
const transaction = route.params?.transaction;
navigation.addListener('focus', () => {
this.props.TransactionsStore.resetBroadcast();
const note = transaction.getNote;
this.setState({ storedNote: note });
});
}
render() {
const { NodeInfoStore, navigation, route } = this.props;
const transaction = route.params?.transaction;
const { storedNote } = this.state;
const { testnet } = NodeInfoStore;
const {
tx,
isConfirmed,
block_hash,
getBlockHeight,
num_confirmations,
time_stamp,
destAddresses,
getFee,
getFeePercentage,
status,
getOutpoint,
raw_tx_hex,
getNoteKey
} = transaction;
const amount = transaction.getAmount;
const date = time_stamp && new Date(Number(time_stamp) * 1000);
const addresses: Array<any> = [];
destAddresses.length > 1
? `${localeString('views.Transaction.destAddresses')}:`
: `${localeString('views.Transaction.destAddress')}:`;
forEach(destAddresses, (address: any, key: string) =>
addresses.push(
<KeyValue
keyValue={
destAddresses.length > 1
? `${localeString(
'views.Transaction.destAddresses'
)} #${Number(key) + 1}`
: localeString('views.Transaction.destAddress')
}
value={
<TouchableOpacity
key={`${address}-${key}`}
onPress={() =>
UrlUtils.goToBlockExplorerAddress(
address,
testnet
)
}
>
<Text
style={{
...styles.valueWithLink,
color: themeColor('highlight')
}}
>
{`${
typeof address === 'string' &&
PrivacyUtils.sensitiveValue({
input: address
})
}`}
</Text>
</TouchableOpacity>
}
key={key}
sensitive
/>
)
);
const EditNotesButton = () => (
<TouchableOpacity
onPress={() =>
navigation.navigate('AddNotes', { noteKey: getNoteKey })
}
>
<EditNotes
style={{ alignSelf: 'center' }}
fill={themeColor('text')}
/>
</TouchableOpacity>
);
return (
<Screen>
<Header
leftComponent="Back"
centerComponent={{
text: localeString('views.Transaction.title'),
style: {
color: themeColor('text'),
fontFamily: 'PPNeueMontreal-Book'
}
}}
rightComponent={<EditNotesButton />}
navigation={navigation}
/>
<View style={styles.center}>
<Amount
sats={amount}
debit={Number(amount) <= 0}
credit={Number(amount) > 0}
sensitive
jumboText
toggleable
/>
</View>
<ScrollView
style={styles.content}
keyboardShouldPersistTaps="handled"
>
{getFee ? (
<KeyValue
keyValue={localeString(
'views.Transaction.totalFees'
)}
value={
<Row>
<Amount
sats={getFee || 0}
debit
toggleable
sensitive
/>
{getFeePercentage && (
<Text
style={{
fontFamily:
'PPNeueMontreal-Book',
color: themeColor('text')
}}
>
{` (${getFeePercentage})`}
</Text>
)}
</Row>
}
/>
) : null}
<KeyValue
keyValue={localeString(
'views.Transaction.transactionHash'
)}
value={
<TouchableOpacity
onPress={() =>
UrlUtils.goToBlockExplorerTXID(tx, testnet)
}
>
<Text
style={{
...styles.valueWithLink,
color: themeColor('highlight')
}}
>
{`${
typeof tx === 'string' &&
PrivacyUtils.sensitiveValue({
input: tx
})
}`}
</Text>
</TouchableOpacity>
}
/>
{!!block_hash && (
<KeyValue
keyValue={localeString(
'views.Transaction.blockHash'
)}
value={
<TouchableOpacity
onPress={() =>
UrlUtils.goToBlockExplorerBlockHash(
block_hash,
testnet
)
}
>
<Text
style={{
...styles.valueWithLink,
color: themeColor('highlight')
}}
>
{`${
typeof block_hash === 'string' &&
PrivacyUtils.sensitiveValue({
input: block_hash
})
}`}
</Text>
</TouchableOpacity>
}
/>
)}
{!!getBlockHeight && (
<KeyValue
keyValue={localeString(
'views.Transaction.blockHeight'
)}
value={
<TouchableOpacity
onPress={() =>
UrlUtils.goToBlockExplorerBlockHeight(
getBlockHeight.toString(),
testnet
)
}
>
<Text
style={{
...styles.valueWithLink,
color: themeColor('highlight')
}}
>
{`${
typeof getBlockHeight ===
'string' &&
PrivacyUtils.sensitiveValue({
input: getBlockHeight.toString(),
fixedLength: 5,
numberSet: true
})
}`}
</Text>
</TouchableOpacity>
}
/>
)}
{!!num_confirmations && !isNull(num_confirmations) && (
<KeyValue
keyValue={localeString('views.Transaction.numConf')}
value={num_confirmations}
color={num_confirmations > 0 ? 'green' : 'red'}
sensitive
/>
)}
{!!status && (
<KeyValue
keyValue={localeString('views.Transaction.status')}
value={status}
/>
)}
{!!date && (
<KeyValue
keyValue={localeString(
'views.Transaction.timestamp'
)}
value={date.toString()}
sensitive
/>
)}
{!!destAddresses && (
<React.Fragment>{addresses}</React.Fragment>
)}
{raw_tx_hex && (
<>
<TouchableOpacity
onPress={() =>
navigation.navigate('RawTxHex', {
value: raw_tx_hex
})
}
>
<View
style={{
marginTop: 10,
marginBottom: 10
}}
>
<Row justify="space-between">
<View style={{ flex: 1 }}>
<KeyValue
keyValue={localeString(
'views.Transaction.rawTxHex'
)}
/>
</View>
<CaretRight
fill={themeColor('text')}
width="20"
height="20"
/>
</Row>
</View>
</TouchableOpacity>
</>
)}
{storedNote && (
<TouchableOpacity
onPress={() =>
navigation.navigate('AddNotes', {
noteKey: getNoteKey
})
}
>
<KeyValue
keyValue={localeString('general.note')}
value={storedNote}
sensitive
/>
</TouchableOpacity>
)}
</ScrollView>
<View style={{ bottom: 15 }}>
{!isConfirmed && BackendUtils.supportsBumpFee() && (
<Button
title={localeString('views.BumpFee.title')}
onPress={() =>
navigation.navigate('BumpFee', {
outpoint: getOutpoint
})
}
noUppercase
containerStyle={{ marginTop: 20 }}
/>
)}
{getNoteKey && (
<Button
title={
storedNote
? localeString(
'views.SendingLightning.UpdateNote'
)
: localeString(
'views.SendingLightning.AddANote'
)
}
onPress={() =>
navigation.navigate('AddNotes', {
noteKey: getNoteKey
})
}
containerStyle={{ marginTop: 20 }}
noUppercase
/>
)}
</View>
</Screen>
);
}
}
const styles = StyleSheet.create({
content: {
paddingLeft: 20,
paddingRight: 20
},
center: {
alignItems: 'center',
paddingTop: 15,
paddingBottom: 15
},
valueWithLink: {
paddingBottom: 5,
fontFamily: 'PPNeueMontreal-Book'
}
});