/* global alert */ import React, { useContext, useEffect, useState } from 'react'; import { View, ScrollView, TouchableOpacity, Text, TextInput, Linking, StatusBar, StyleSheet, Keyboard } from 'react-native'; import { useNavigation, useRoute, useTheme } from '@react-navigation/native'; import { BlueCard, BlueCopyToClipboardButton, BlueLoading, BlueSpacing20, BlueText, SafeBlueArea } from '../../BlueComponents'; import navigationStyle from '../../components/navigationStyle'; import HandoffComponent from '../../components/handoff'; import loc from '../../loc'; import { BlueStorageContext } from '../../blue_modules/storage-context'; import Clipboard from '@react-native-clipboard/clipboard'; import ToolTipMenu from '../../components/TooltipMenu'; const dayjs = require('dayjs'); function onlyUnique(value, index, self) { return self.indexOf(value) === index; } function arrDiff(a1, a2) { const ret = []; for (const v of a2) { if (a1.indexOf(v) === -1) { ret.push(v); } } return ret; } const TransactionsDetails = () => { const { setOptions } = useNavigation(); const { hash } = useRoute().params; const { saveToDisk, txMetadata, wallets, getTransactions } = useContext(BlueStorageContext); const [from, setFrom] = useState(); const [to, setTo] = useState(); const [isLoading, setIsLoading] = useState(true); const [tx, setTX] = useState(); const [memo, setMemo] = useState(); const { colors } = useTheme(); const stylesHooks = StyleSheet.create({ txLink: { color: colors.alternativeTextColor2, }, saveText: { color: colors.alternativeTextColor2, }, memoTextInput: { borderColor: colors.formBorder, borderBottomColor: colors.formBorder, backgroundColor: colors.inputBackgroundColor, }, greyButton: { backgroundColor: colors.lightButton, }, Link: { color: colors.buttonTextColor, }, }); useEffect(() => { setOptions({ headerRight: () => ( {loc.wallets.details_save} ), }); // eslint-disable-next-line react-hooks/exhaustive-deps }, [colors, isLoading, memo]); useEffect(() => { let foundTx = {}; let from = []; let to = []; for (const tx of getTransactions(null, Infinity, true)) { if (tx.hash === hash) { foundTx = tx; for (const input of foundTx.inputs) { from = from.concat(input.addresses); } for (const output of foundTx.outputs) { if (output.addresses) to = to.concat(output.addresses); if (output.scriptPubKey && output.scriptPubKey.addresses) to = to.concat(output.scriptPubKey.addresses); } } } for (const w of wallets) { for (const t of w.getTransactions()) { if (t.hash === hash) { console.log('tx', hash, 'belongs to', w.getLabel()); } } } if (txMetadata[foundTx.hash]) { if (txMetadata[foundTx.hash].memo) { setMemo(txMetadata[foundTx.hash].memo); } } setTX(foundTx); setFrom(from); setTo(to); setIsLoading(false); // eslint-disable-next-line react-hooks/exhaustive-deps }, [hash, wallets]); const handleOnSaveButtonTapped = () => { Keyboard.dismiss(); txMetadata[tx.hash] = { memo }; saveToDisk().then(_success => alert(loc.transactions.transaction_note_saved)); }; const handleOnOpenTransactionOnBlockExporerTapped = () => { const url = `https://mempool.space/tx/${tx.hash}`; Linking.canOpenURL(url).then(supported => { if (supported) { Linking.openURL(url); } }); }; const handleCopyPress = () => { Clipboard.setString(`https://mempool.space/tx/${tx.hash}`); }; if (isLoading || !tx) { return ; } return ( {from && ( <> {loc.transactions.details_from} {from.filter(onlyUnique).join(', ')} )} {to && ( <> {loc.transactions.details_to} {arrDiff(from, to.filter(onlyUnique)).join(', ')} )} {tx.fee && ( <> {loc.send.create_fee} {tx.fee + ' sats'} )} {tx.hash && ( <> {loc.transactions.txid} {tx.hash} )} {tx.received && ( <> {loc.transactions.details_received} {dayjs(tx.received).format('LLL')} )} {tx.block_height > 0 && ( <> {loc.transactions.details_block} {tx.block_height} )} {tx.inputs && ( <> {loc.transactions.details_inputs} {tx.inputs.length} )} {tx.outputs?.length > 0 && ( <> {loc.transactions.details_outputs} {tx.outputs.length} )} {loc.transactions.details_show_in_block_explorer} ); }; TransactionsDetails.actionKeys = { CopyToClipboard: 'copyToClipboard', }; TransactionsDetails.actionIcons = { Clipboard: { iconType: 'SYSTEM', iconValue: 'doc.on.doc', }, }; const styles = StyleSheet.create({ scroll: { flex: 1, }, rowHeader: { flex: 1, flexDirection: 'row', marginBottom: 4, justifyContent: 'space-between', }, rowCaption: { fontSize: 16, fontWeight: '500', marginBottom: 4, }, rowValue: { marginBottom: 26, color: 'grey', }, txId: { fontSize: 16, fontWeight: '500', }, txHash: { marginBottom: 8, color: 'grey', }, Link: { fontWeight: '600', fontSize: 15, }, save: { justifyContent: 'center', alignItems: 'center', }, memoTextInput: { flexDirection: 'row', borderWidth: 1, borderBottomWidth: 0.5, minHeight: 44, height: 44, alignItems: 'center', marginVertical: 8, borderRadius: 4, paddingHorizontal: 8, color: '#81868e', }, greyButton: { borderRadius: 9, minHeight: 49, paddingHorizontal: 8, justifyContent: 'center', alignItems: 'center', flexDirection: 'row', alignSelf: 'auto', flexGrow: 1, marginHorizontal: 4, }, }); export default TransactionsDetails; TransactionsDetails.navigationOptions = navigationStyle( { headerTitle: loc.transactions.details_title }, (options, { theme, navigation, route }) => { return { ...options, headerStyle: { backgroundColor: theme.colors.customHeader, borderBottomWidth: 0, elevation: 0, shadowOpacity: 0, shadowOffset: { height: 0, width: 0 }, }, }; }, );