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

242 lines
7.2 KiB
TypeScript

import * as React from 'react';
import { Animated, View, StyleSheet } from 'react-native';
import { inject, observer } from 'mobx-react';
import { Route } from '@react-navigation/native';
import { StackNavigationProp } from '@react-navigation/stack';
import Button from '../components/Button';
import CurrencySelectorModal from '../components/CurrencySelectorModal';
import Header from '../components/Header';
import KeypadAmountDisplay from '../components/KeypadAmountDisplay';
import PinPad from '../components/PinPad';
import Screen from '../components/Screen';
import UnitToggle from '../components/UnitToggle';
import FiatStore from '../stores/FiatStore';
import SettingsStore from '../stores/SettingsStore';
import UnitsStore from '../stores/UnitsStore';
import { themeColor } from '../utils/ThemeUtils';
import {
validateKeypadInput,
startShakeAnimation,
getAmountFontSize,
deleteLastCharacter
} from '../utils/KeypadUtils';
import { getDecimalPlaceholder } from '../utils/UnitsUtils';
import { localeString } from '../utils/LocaleUtils';
interface AmountKeypadProps {
navigation: StackNavigationProp<any, any>;
route: Route<
'AmountKeypad',
{
initialAmount?: string;
hideUnitChangeButton?: boolean;
forceUnit?: 'sats' | 'BTC' | 'fiat';
onConfirm?: (amount: string) => void;
}
>;
FiatStore?: FiatStore;
SettingsStore?: SettingsStore;
UnitsStore?: UnitsStore;
}
interface AmountKeypadState {
amount: string;
}
@inject('FiatStore', 'SettingsStore', 'UnitsStore')
@observer
export default class AmountKeypad extends React.Component<
AmountKeypadProps,
AmountKeypadState
> {
shakeAnimation = new Animated.Value(0);
textAnimation = new Animated.Value(0);
private currencySelectorModalRef = React.createRef<CurrencySelectorModal>();
constructor(props: AmountKeypadProps) {
super(props);
const initialAmount = props.route.params?.initialAmount || '0';
this.state = {
amount: initialAmount
};
}
getEffectiveUnits = (): string => {
const forceUnit = this.props.route.params?.forceUnit;
return forceUnit || this.props.UnitsStore!.units;
};
appendValue = (value: string): boolean => {
const { amount } = this.state;
const { FiatStore, SettingsStore } = this.props;
const units = this.getEffectiveUnits();
const { valid, newAmount } = validateKeypadInput(
amount,
value,
units,
FiatStore!,
SettingsStore!
);
if (!valid) {
this.startShake();
return false;
}
this.setState({ amount: newAmount });
return true;
};
clearValue = () => {
this.setState({ amount: '0' });
};
deleteValue = () => {
const { amount } = this.state;
if (amount === '0') {
this.startShake();
return;
}
this.setState({ amount: deleteLastCharacter(amount) });
};
startShake = () => {
startShakeAnimation(this.shakeAnimation, this.textAnimation);
};
handleConfirm = () => {
const { amount } = this.state;
const { navigation, route } = this.props;
const { onConfirm } = route.params || {};
if (onConfirm) {
onConfirm(amount);
}
navigation.goBack();
};
handleUnitToggle = () => {
this.clearValue();
};
handleOpenCurrencyModal = () => {
this.currencySelectorModalRef.current?.open();
};
handleCurrencyModalClose = () => {
this.clearValue();
};
getAmountFontSize = () => {
const { amount } = this.state;
const units = this.getEffectiveUnits();
const { count } = getDecimalPlaceholder(amount, units);
return getAmountFontSize(amount.length, count);
};
render() {
const { navigation, route } = this.props;
const { amount } = this.state;
const hideUnitChangeButton = route.params?.hideUnitChangeButton;
const forceUnit = route.params?.forceUnit;
const fontSize = this.getAmountFontSize();
return (
<Screen>
<Header
leftComponent="Back"
centerComponent={{
text: localeString('general.amount'),
style: {
color: themeColor('text'),
fontFamily: 'PPNeueMontreal-Book'
}
}}
navigation={navigation}
/>
<View style={styles.container}>
<View style={styles.amountDisplayContainer}>
<KeypadAmountDisplay
amount={amount}
shakeAnimation={this.shakeAnimation}
textAnimation={this.textAnimation}
fontSize={fontSize}
forceUnit={forceUnit}
showConversion
>
{!hideUnitChangeButton && !forceUnit && (
<View style={styles.unitToggleContainer}>
<UnitToggle
onToggle={this.handleUnitToggle}
onOpenModal={
this.handleOpenCurrencyModal
}
/>
</View>
)}
</KeypadAmountDisplay>
</View>
{/* PinPad */}
<View style={styles.pinPadContainer}>
<PinPad
appendValue={this.appendValue}
clearValue={this.clearValue}
deleteValue={this.deleteValue}
numberHighlight
amount
/>
</View>
{/* Done Button */}
<View style={styles.buttonContainer}>
<Button
title={localeString('general.confirm')}
onPress={this.handleConfirm}
containerStyle={styles.doneButton}
/>
</View>
</View>
<CurrencySelectorModal
ref={this.currencySelectorModalRef}
navigation={navigation}
onClose={this.handleCurrencyModalClose}
/>
</Screen>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingHorizontal: 20
},
amountDisplayContainer: {
flex: 1,
alignItems: 'center',
marginTop: 60
},
unitToggleContainer: {
alignItems: 'center',
marginVertical: 15
},
pinPadContainer: {
flex: 1,
justifyContent: 'center'
},
buttonContainer: {
paddingBottom: 20
},
doneButton: {
borderRadius: 12
}
});