import React, { useState, useRef, forwardRef, useImperativeHandle } from 'react'; import { View, Text, TouchableOpacity, TextInput, StyleSheet, Platform } from 'react-native'; import BottomModal, { BottomModalHandle } from './BottomModal'; import { useTheme } from './themes'; import loc, { formatBalance } from '../loc'; import { SecondButton } from './SecondButton'; import { BitcoinUnit } from '../models/bitcoinUnits'; interface NetworkTransactionFees { fastestFee: number; mediumFee: number; slowFee: number; } interface FeePrecalc { fastestFee: number | null; mediumFee: number | null; slowFee: number | null; current: number | null; } interface Option { label: string; time: string; fee: number | null; rate: number; active: boolean; disabled?: boolean; } interface SelectFeeModalProps { networkTransactionFees: NetworkTransactionFees; feePrecalc: FeePrecalc; feeRate: number | string; setCustomFee: (fee: string) => void; setFeePrecalc: (fn: (fp: FeePrecalc) => FeePrecalc) => void; feeUnit: BitcoinUnit; } const SelectFeeModal = forwardRef( ({ networkTransactionFees, feePrecalc, feeRate, setCustomFee, setFeePrecalc, feeUnit }, ref) => { const [customFee, setCustomFeeState] = useState(''); const feeModalRef = useRef(null); const customModalRef = useRef(null); const nf = networkTransactionFees; const { colors } = useTheme(); const stylesHook = StyleSheet.create({ loading: { backgroundColor: colors.background, }, root: { backgroundColor: colors.elevated, }, feeModalItemActive: { backgroundColor: colors.feeActive, }, feeModalLabel: { color: colors.successColor, }, feeModalTime: { backgroundColor: colors.successColor, }, feeModalTimeText: { color: colors.background, }, feeModalValue: { color: colors.successColor, }, feeModalCustomText: { color: colors.buttonAlternativeTextColor, }, selectLabel: { color: colors.buttonTextColor, }, of: { color: colors.feeText, }, memo: { borderColor: colors.formBorder, borderBottomColor: colors.formBorder, backgroundColor: colors.inputBackgroundColor, }, feeLabel: { color: colors.feeText, }, feeModalItemDisabled: { backgroundColor: colors.buttonDisabledBackgroundColor, }, feeModalItemTextDisabled: { color: colors.buttonDisabledTextColor, }, feeRow: { backgroundColor: colors.feeLabel, }, feeValue: { color: colors.feeValue, }, }); useImperativeHandle(ref, () => ({ present: async () => feeModalRef.current?.present(), dismiss: async () => feeModalRef.current?.dismiss(), })); const options: Option[] = [ { label: loc.send.fee_fast, time: loc.send.fee_10m, fee: feePrecalc.fastestFee, rate: nf.fastestFee, active: Number(feeRate) === nf.fastestFee, }, { label: loc.send.fee_medium, time: loc.send.fee_3h, fee: feePrecalc.mediumFee, rate: nf.mediumFee, active: Number(feeRate) === nf.mediumFee, disabled: nf.mediumFee === nf.fastestFee, }, { label: loc.send.fee_slow, time: loc.send.fee_1d, fee: feePrecalc.slowFee, rate: nf.slowFee, active: Number(feeRate) === nf.slowFee, disabled: nf.slowFee === nf.mediumFee || nf.slowFee === nf.fastestFee, }, ]; const formatFee = (fee: number) => formatBalance(fee, feeUnit!, true); const handleCustomFeeSubmit = async () => { if (!/^\d+$/.test(customFee) || Number(customFee) <= 0) { // Handle error if necessary return; } const fee = Number(customFee) < 1 ? '1' : customFee; setCustomFee(fee); await customModalRef.current?.dismiss(); await feeModalRef.current?.dismiss(); }; const handleCancel = async () => { setCustomFeeState(''); await customModalRef.current?.dismiss(); }; const handlePressCustom = async () => { await customModalRef.current?.present(); }; const handleSelectOption = async (fee: number | null, rate: number) => { setFeePrecalc(fp => ({ ...fp, current: fee })); await feeModalRef.current?.dismiss(); setCustomFee(rate.toString()); }; return ( {loc.send.fee_custom} } > {options.map(({ label, time, fee, rate, active, disabled }) => ( handleSelectOption(fee, rate)} style={[styles.feeModalItem, active && styles.feeModalItemActive, active && !disabled && stylesHook.feeModalItemActive]} > {label} ~{time} {fee && formatFee(fee)} {rate} {loc.units.sat_vbyte} ))} } footerDefaultMargins > {loc.send.insert_custom_fee} ); }, ); export default SelectFeeModal; const styles = StyleSheet.create({ loading: { flex: 1, paddingTop: 20, }, root: { flex: 1, justifyContent: 'space-between', }, scrollViewContent: { flexDirection: 'row', }, scrollViewIndicator: { top: 0, left: 8, bottom: 0, right: 8, }, modalContent: { margin: 22, }, modalContentMinHeight: Platform.OS === 'android' ? { minHeight: 400 } : {}, paddingTop66: { paddingVertical: 66 }, paddingTop30: { paddingBottom: 60, paddingTop: 30 }, optionsContent: { padding: 22, }, feeModalItem: { paddingHorizontal: 16, paddingVertical: 8, marginBottom: 10, }, feeModalItemActive: { borderRadius: 8, }, feeModalRow: { justifyContent: 'space-between', flexDirection: 'row', alignItems: 'center', }, feeModalLabel: { fontSize: 22, fontWeight: '600', }, customFeeTextInput: { backgroundColor: '#FFFFFF', borderColor: '#9aa0aa', borderWidth: 1, borderRadius: 4, padding: 8, marginVertical: 8, fontSize: 16, }, feeModalTime: { borderRadius: 5, paddingHorizontal: 6, paddingVertical: 3, }, feeModalCustomText: { fontSize: 15, fontWeight: '600', }, createButton: { marginVertical: 16, marginHorizontal: 16, alignContent: 'center', minHeight: 44, }, select: { marginBottom: 24, marginHorizontal: 24, alignItems: 'center', }, selectTouch: { flexDirection: 'row', alignItems: 'center', }, selectText: { color: '#9aa0aa', fontSize: 14, marginRight: 8, }, selectWrap: { flexDirection: 'row', alignItems: 'center', marginVertical: 4, }, selectLabel: { fontSize: 14, }, of: { alignSelf: 'flex-end', marginRight: 18, marginVertical: 8, }, feeModalFooter: { paddingBottom: 36, flexDirection: 'row', justifyContent: 'space-between', }, feeModalFooterSpacing: { paddingHorizontal: 24, }, memo: { flexDirection: 'row', borderWidth: 1, borderBottomWidth: 0.5, minHeight: 44, height: 44, marginHorizontal: 20, alignItems: 'center', marginVertical: 8, borderRadius: 4, }, memoText: { flex: 1, marginHorizontal: 8, minHeight: 33, color: '#81868e', }, fee: { flexDirection: 'row', marginHorizontal: 20, justifyContent: 'space-between', alignItems: 'center', }, feeLabel: { fontSize: 14, }, feeRow: { minWidth: 40, height: 25, borderRadius: 4, justifyContent: 'space-between', flexDirection: 'row', alignItems: 'center', paddingHorizontal: 10, }, advancedOptions: { minWidth: 40, height: 40, justifyContent: 'center', }, feeModalCloseButton: { paddingHorizontal: 10, paddingVertical: 8, }, feeModalCloseButtonText: { color: '#007AFF', }, });