mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-20 03:42:10 +03:00
Merge pull request #2269 from ecency/sa/power-down-screen
[WIP] Redesign Power Down Screen
This commit is contained in:
commit
d0b1dedfe5
@ -0,0 +1,377 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, FlatList, Text, TouchableOpacity } from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { isArray, debounce } from 'lodash';
|
||||
|
||||
import styles from './styles';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from '../../hooks';
|
||||
import { BeneficiaryModal, CheckBox, FormInput, IconButton, TextButton } from '../../components';
|
||||
import { Beneficiary } from '../../redux/reducers/editorReducer';
|
||||
import { lookupAccounts } from '../../providers/hive/dhive';
|
||||
import { TEMP_BENEFICIARIES_ID } from '../../redux/constants/constants';
|
||||
import {
|
||||
removeBeneficiaries,
|
||||
setBeneficiaries as setBeneficiariesAction,
|
||||
} from '../../redux/actions/editorActions';
|
||||
|
||||
interface BeneficiarySelectionContentProps {
|
||||
|
||||
draftId: string;
|
||||
setDisableDone: (value: boolean) => void;
|
||||
powerDown?: boolean;
|
||||
label?:string;
|
||||
labelStyle?:string;
|
||||
powerDownBeneficiaries?: Beneficiary[];
|
||||
handleSaveBeneficiary?: (beneficiaries: Beneficiary[]) => void;
|
||||
handleRemoveBeneficiary?: (beneficiary: Beneficiary) => void;
|
||||
}
|
||||
|
||||
const BeneficiarySelectionContent = ({
|
||||
label,
|
||||
labelStyle,
|
||||
draftId,
|
||||
setDisableDone,
|
||||
powerDown,
|
||||
powerDownBeneficiaries,
|
||||
handleSaveBeneficiary,
|
||||
handleRemoveBeneficiary,
|
||||
}: BeneficiarySelectionContentProps) => {
|
||||
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const beneficiariesMap = useAppSelector((state) => state.editor.beneficiariesMap);
|
||||
const username = useAppSelector((state) => state.account.currentAccount.name);
|
||||
|
||||
const [beneficiaries, setBeneficiaries] = useState<Beneficiary[]>([
|
||||
{ account: username, weight: 10000, autoPowerUp: false },
|
||||
]);
|
||||
|
||||
const [newUsername, setNewUsername] = useState('');
|
||||
const [newWeight, setNewWeight] = useState(0);
|
||||
const [newAutoPowerUp, setNewAutoPowerUp] = useState(false);
|
||||
const [isUsernameValid, setIsUsernameValid] = useState(false);
|
||||
const [isWeightValid, setIsWeightValid] = useState(false);
|
||||
const [newEditable, setNewEditable] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (powerDown) {
|
||||
readPowerDownBeneficiaries();
|
||||
}
|
||||
}, [powerDownBeneficiaries]);
|
||||
|
||||
useEffect(() => {
|
||||
if (draftId) {
|
||||
readTempBeneficiaries();
|
||||
}
|
||||
}, [draftId]);
|
||||
|
||||
useEffect(() => {
|
||||
setDisableDone(newEditable);
|
||||
}, [newEditable]);
|
||||
|
||||
const readPowerDownBeneficiaries = () => {
|
||||
const tempBeneficiaries = [
|
||||
{ account: username, weight: 10000, autoPowerUp: false },
|
||||
...powerDownBeneficiaries,
|
||||
];
|
||||
|
||||
if (isArray(tempBeneficiaries) && tempBeneficiaries.length > 0) {
|
||||
//weight correction algorithm.
|
||||
let othersWeight = 0;
|
||||
tempBeneficiaries.forEach((item, index) => {
|
||||
if (index > 0) {
|
||||
othersWeight += item.weight;
|
||||
}
|
||||
});
|
||||
tempBeneficiaries[0].weight = 10000 - othersWeight;
|
||||
|
||||
setBeneficiaries([...tempBeneficiaries]);
|
||||
}
|
||||
};
|
||||
|
||||
const readTempBeneficiaries = async () => {
|
||||
if (beneficiariesMap) {
|
||||
const tempBeneficiaries = beneficiariesMap[draftId || TEMP_BENEFICIARIES_ID];
|
||||
|
||||
if (isArray(tempBeneficiaries) && tempBeneficiaries.length > 0) {
|
||||
//weight correction algorithm.
|
||||
let othersWeight = 0;
|
||||
tempBeneficiaries.forEach((item, index) => {
|
||||
if (index > 0) {
|
||||
othersWeight += item.weight;
|
||||
}
|
||||
});
|
||||
tempBeneficiaries[0].weight = 10000 - othersWeight;
|
||||
|
||||
setBeneficiaries(tempBeneficiaries);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _saveBeneficiaries = (value: Beneficiary[]) => {
|
||||
if (handleSaveBeneficiary) {
|
||||
handleSaveBeneficiary(value);
|
||||
} else {
|
||||
dispatch(setBeneficiariesAction(draftId || TEMP_BENEFICIARIES_ID, value));
|
||||
}
|
||||
};
|
||||
|
||||
const _onSavePress = () => {
|
||||
if (newEditable) {
|
||||
beneficiaries.push({
|
||||
account: newUsername,
|
||||
weight: newWeight,
|
||||
autoPowerUp: newAutoPowerUp,
|
||||
});
|
||||
}
|
||||
_saveBeneficiaries(beneficiaries);
|
||||
_resetInputs(false);
|
||||
};
|
||||
|
||||
const _addAccount = () => {
|
||||
if (isUsernameValid && isWeightValid) {
|
||||
beneficiaries.push({
|
||||
account: newUsername,
|
||||
weight: newWeight,
|
||||
});
|
||||
setBeneficiaries([...beneficiaries]);
|
||||
}
|
||||
|
||||
setIsUsernameValid(false);
|
||||
setIsWeightValid(false);
|
||||
setNewWeight(0);
|
||||
setNewUsername('');
|
||||
setNewEditable(true);
|
||||
};
|
||||
|
||||
const _onWeightInputChange = (value: string) => {
|
||||
let _value = (parseInt(value, 10) || 0) * 100;
|
||||
|
||||
const _diff = _value - newWeight;
|
||||
const newAuthorWeight = beneficiaries[0].weight - _diff;
|
||||
beneficiaries[0].weight = newAuthorWeight;
|
||||
|
||||
setNewWeight(_value);
|
||||
setIsWeightValid(_value >= 0 && newAuthorWeight >= 0);
|
||||
setBeneficiaries([...beneficiaries]);
|
||||
};
|
||||
|
||||
const _lookupAccounts = debounce((username) => {
|
||||
lookupAccounts(username).then((res) => {
|
||||
const isValid = res.includes(username);
|
||||
//check if username duplicates else lookup contacts, done here to avoid debounce and post call mismatch
|
||||
const notExistAlready = !beneficiaries.find((item) => item.account === username);
|
||||
setIsUsernameValid(isValid && notExistAlready);
|
||||
});
|
||||
}, 1000);
|
||||
|
||||
const _onUsernameInputChange = (value) => {
|
||||
setNewUsername(value);
|
||||
_lookupAccounts(value);
|
||||
};
|
||||
|
||||
const _resetInputs = (adjustWeight = true) => {
|
||||
if (newWeight && adjustWeight) {
|
||||
beneficiaries[0].weight = beneficiaries[0].weight + newWeight;
|
||||
setBeneficiaries([...beneficiaries]);
|
||||
}
|
||||
|
||||
setNewWeight(0);
|
||||
setNewEditable(false);
|
||||
setIsWeightValid(false);
|
||||
setIsUsernameValid(false);
|
||||
setNewUsername('');
|
||||
};
|
||||
|
||||
const _renderHeader = () => (
|
||||
<View style={styles.inputWrapper}>
|
||||
{powerDown && (
|
||||
<View style={{ ...styles.checkBoxHeader, marginTop: 4 }}>
|
||||
<Text style={styles.contentLabel}>
|
||||
{intl.formatMessage({ id: 'transfer.auto_vests' })}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View style={{ ...styles.weightInput, marginTop: 4 }}>
|
||||
<Text style={styles.contentLabel}>
|
||||
{intl.formatMessage({
|
||||
id: 'beneficiary_modal.percent',
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ ...styles.usernameInput, marginTop: 4, marginLeft: 28 }}>
|
||||
<Text style={styles.contentLabel}>
|
||||
{intl.formatMessage({
|
||||
id: 'beneficiary_modal.username',
|
||||
})}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const _handleCheckboxClick = (value, isCheck) => {
|
||||
setNewAutoPowerUp(isCheck);
|
||||
};
|
||||
const _renderCheckBox = ({ locked, isChecked }: { locked: boolean; isChecked: boolean }) => (
|
||||
<View style={styles.checkBoxContainer}>
|
||||
<CheckBox
|
||||
locked={locked}
|
||||
isChecked={isChecked}
|
||||
clicked={_handleCheckboxClick}
|
||||
value={newAutoPowerUp}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
const _renderInput = () => {
|
||||
return (
|
||||
<View style={styles.inputWrapper}>
|
||||
{powerDown && _renderCheckBox({ locked: false, isChecked: false })}
|
||||
<View style={styles.weightInput}>
|
||||
<FormInput
|
||||
isValid={isWeightValid}
|
||||
value={`${newWeight / 100}`}
|
||||
inputStyle={styles.weightFormInput}
|
||||
wrapperStyle={styles.weightFormInputWrapper}
|
||||
onChange={(value) => _onWeightInputChange(value)}
|
||||
selectTextOnFocus={true}
|
||||
autoFocus={true}
|
||||
returnKeyType={'next'}
|
||||
keyboardType="numeric"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.usernameInput}>
|
||||
<FormInput
|
||||
rightIconName="at"
|
||||
iconType="MaterialCommunityIcons"
|
||||
isValid={isUsernameValid}
|
||||
onChange={(value) => _onUsernameInputChange(value.trim())}
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'beneficiary_modal.username',
|
||||
})}
|
||||
type="username"
|
||||
isFirstImage
|
||||
returnKeyType="done"
|
||||
value={newUsername}
|
||||
onSubmitEditing={isWeightValid && isUsernameValid && _onSavePress}
|
||||
inputStyle={styles.usernameInput}
|
||||
wrapperStyle={styles.usernameFormInputWrapper}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{isWeightValid && isUsernameValid ? (
|
||||
<IconButton
|
||||
name="check"
|
||||
iconType="MaterialCommunityIcons"
|
||||
color={EStyleSheet.value('$white')}
|
||||
iconStyle={{ marginTop: 2 }}
|
||||
size={24}
|
||||
style={styles.doneButton}
|
||||
onPress={_onSavePress}
|
||||
/>
|
||||
) : (
|
||||
<View style={{ width: 28 }} />
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const _renderFooter = () => (
|
||||
<>
|
||||
{newEditable && _renderInput()}
|
||||
<View style={{ marginTop: 20, marginBottom: 32 }}>
|
||||
<TextButton
|
||||
text={
|
||||
newEditable
|
||||
? intl.formatMessage({
|
||||
id: 'beneficiary_modal.cancel',
|
||||
})
|
||||
: intl.formatMessage({
|
||||
id: 'beneficiary_modal.addAccount',
|
||||
})
|
||||
}
|
||||
onPress={newEditable ? _resetInputs : _addAccount}
|
||||
textStyle={{
|
||||
color: EStyleSheet.value('$primaryBlue'),
|
||||
fontWeight: 'bold',
|
||||
textAlign: 'left',
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
||||
const _renderItem = ({ item, index }) => {
|
||||
const _isCurrentUser = item.account === username;
|
||||
|
||||
const _onRemovePress = () => {
|
||||
beneficiaries[0].weight = beneficiaries[0].weight + item.weight;
|
||||
const removedBeneficiary = beneficiaries.splice(index, 1);
|
||||
setBeneficiaries([...beneficiaries]);
|
||||
if(handleRemoveBeneficiary){
|
||||
handleRemoveBeneficiary(removedBeneficiary[0]);
|
||||
return;
|
||||
}
|
||||
_saveBeneficiaries(beneficiaries);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.inputWrapper}>
|
||||
{powerDown && _renderCheckBox({ locked: true, isChecked: item.autoPowerUp })}
|
||||
<View style={styles.weightInput}>
|
||||
<FormInput
|
||||
isValid={true}
|
||||
isEditable={false}
|
||||
value={`${item.weight / 100}`}
|
||||
inputStyle={styles.weightFormInput}
|
||||
wrapperStyle={styles.weightFormInputWrapper}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.usernameInput}>
|
||||
<FormInput
|
||||
isValid={true}
|
||||
isEditable={false}
|
||||
type="username"
|
||||
isFirstImage
|
||||
value={item.account}
|
||||
inputStyle={styles.usernameInput}
|
||||
wrapperStyle={styles.usernameFormInputWrapper}
|
||||
/>
|
||||
</View>
|
||||
{!_isCurrentUser ? (
|
||||
<IconButton
|
||||
name="close"
|
||||
iconType="MaterialCommunityIcons"
|
||||
size={24}
|
||||
color={EStyleSheet.value('$primaryBlack')}
|
||||
iconStyle={{ paddingLeft: 8 }}
|
||||
onPress={_onRemovePress}
|
||||
/>
|
||||
) : (
|
||||
<View style={{ width: 30 }} />
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={labelStyle || styles.settingLabel}>{label || intl.formatMessage({ id: 'editor.beneficiaries' })}</Text>
|
||||
<FlatList
|
||||
data={beneficiaries}
|
||||
renderItem={_renderItem}
|
||||
ListHeaderComponent={_renderHeader}
|
||||
showsVerticalScrollIndicator={false}
|
||||
/>
|
||||
{_renderFooter()}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default BeneficiarySelectionContent;
|
65
src/components/beneficiarySelectionContent/styles.ts
Normal file
65
src/components/beneficiarySelectionContent/styles.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { getBottomSpace } from 'react-native-iphone-x-helper';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
|
||||
sheetContent: {
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
position:'absolute',
|
||||
bottom:0,
|
||||
left:0,
|
||||
right:0,
|
||||
zIndex:999
|
||||
},
|
||||
thumbStyle:{
|
||||
width:72,
|
||||
height:72,
|
||||
marginVertical:8,
|
||||
marginRight:8,
|
||||
borderRadius:12,
|
||||
backgroundColor:'$primaryLightGray'
|
||||
},
|
||||
selectedStyle:{
|
||||
borderWidth:4,
|
||||
borderColor:'$primaryBlack'
|
||||
},
|
||||
settingLabel:{
|
||||
color: '$primaryDarkGray',
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
flexGrow: 1,
|
||||
textAlign:'left',
|
||||
},
|
||||
listContainer:{
|
||||
paddingBottom:getBottomSpace() + 16,
|
||||
},
|
||||
container:{
|
||||
paddingVertical:16
|
||||
},
|
||||
bodyWrapper: { flex: 1, paddingTop: 20, paddingBottom:20},
|
||||
inputWrapper: { flexDirection: 'row', alignItems: 'center'},
|
||||
contentLabel: { color: '$iconColor', marginTop:4, textAlign:'left' },
|
||||
weightInput: {width:80},
|
||||
weightFormInput: { flex:1, color: '$primaryBlack', paddingLeft: 12 },
|
||||
weightFormInputWrapper: { marginTop: 8 },
|
||||
usernameInput: { flex:1, color: '$primaryBlack', marginLeft: 16, },
|
||||
usernameFormInputWrapper: { marginTop: 8, marginRight: 12 },
|
||||
footerWrapper: { paddingTop:16 },
|
||||
saveButton: {
|
||||
width: 140,
|
||||
height: 44,
|
||||
alignSelf: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
doneButton:{borderRadius:16, backgroundColor:'$primaryBlue'},
|
||||
thumbSelectContainer:{
|
||||
marginTop:12,
|
||||
},
|
||||
checkBoxHeader: {
|
||||
width: 50,
|
||||
},
|
||||
checkBoxContainer: {
|
||||
width: 50,
|
||||
marginTop:12,
|
||||
}
|
||||
});
|
@ -15,7 +15,7 @@ export default EStyleSheet.create({
|
||||
height: 24,
|
||||
borderRadius: 12,
|
||||
top: 15,
|
||||
marginLeft: 12,
|
||||
marginLeft: 8,
|
||||
},
|
||||
textInput: {
|
||||
flex: 1,
|
||||
|
@ -101,7 +101,7 @@ const FormInputView = ({
|
||||
]}
|
||||
>
|
||||
{isFirstImage && value && value.length > 2 ? (
|
||||
<View style={{ flex: 0.15 }}>
|
||||
<View style={{ flex: 0.2 }}>
|
||||
<FastImage
|
||||
style={styles.firstImage}
|
||||
source={{
|
||||
|
@ -97,6 +97,7 @@ import Tooltip from './tooltip/tooltipView';
|
||||
import VideoPlayer from './videoPlayer/videoPlayerView';
|
||||
import QRModal from './qrModal/qrModalView';
|
||||
import { SimpleChart } from './simpleChart';
|
||||
import BeneficiarySelectionContent from './beneficiarySelectionContent/beneficiarySelectionContent';
|
||||
|
||||
// Basic UI Elements
|
||||
import {
|
||||
@ -243,4 +244,5 @@ export {
|
||||
InsertLinkModal,
|
||||
QRModal,
|
||||
SimpleChart,
|
||||
BeneficiarySelectionContent,
|
||||
};
|
||||
|
@ -576,11 +576,11 @@
|
||||
"stop_information": "Are you sure want to stop?",
|
||||
"percent": "Percent",
|
||||
"auto_vests": "Auto Vests",
|
||||
"vests": "Vests",
|
||||
"save": "SAVE",
|
||||
"percent_information": "Percent info",
|
||||
"next": "NEXT",
|
||||
"delegate": "Delegate",
|
||||
"power_down": "Power Down",
|
||||
"withdraw_hive": "Withdraw HIVE",
|
||||
"withdraw_hbd": "Withdraw HIVE Dollar",
|
||||
"incoming_funds": "Incoming Funds",
|
||||
@ -599,7 +599,16 @@
|
||||
"confirm_summary": "Delegate {hp} HP ({vests} VESTS) To @{delegator} from @{delegatee} ",
|
||||
"confirm_summary_para": "This will overwrite your previous delegation of {prev} HP to this user.",
|
||||
"username_alert": "Username Error!",
|
||||
"username_alert_detail": "Please select different username"
|
||||
"username_alert_detail": "Please select different username",
|
||||
"power_down": "Power Down",
|
||||
"power_down_amount_head": "Withdraw Amount",
|
||||
"power_down_amount_subhead": "Enter amount for powering down hive power",
|
||||
"withdraw_accounts":"Withdraw Accounts",
|
||||
"amount_hp": "Amount (HP)",
|
||||
"powering_down": "Powering Down",
|
||||
"powering_down_subheading": "You are currently powering down.",
|
||||
"powering_down_info": "Next power down is in {days} days, {hp} HIVE"
|
||||
|
||||
},
|
||||
"boost": {
|
||||
"title": "Get Points",
|
||||
|
@ -4,6 +4,7 @@ export interface Beneficiary {
|
||||
account:string,
|
||||
weight:number,
|
||||
isValid?:boolean,
|
||||
autoPowerUp?: boolean,
|
||||
}
|
||||
|
||||
interface State {
|
||||
|
@ -18,7 +18,7 @@ interface BeneficiarySelectionContent {
|
||||
setDisableDone:(value:boolean)=>void;
|
||||
}
|
||||
|
||||
const BeneficiarySelectionContent = ({ draftId, setDisableDone }) => {
|
||||
const BeneficiarySelectionContent = ({ draftId, setDisableDone}) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@ -35,6 +35,7 @@ const BeneficiarySelectionContent = ({ draftId, setDisableDone }) => {
|
||||
const [isWeightValid, setIsWeightValid] = useState(false);
|
||||
const [newEditable, setNewEditable] = useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
readTempBeneficiaries();
|
||||
}, [draftId]);
|
||||
|
@ -1,10 +1,11 @@
|
||||
/* eslint-disable react/no-unused-state */
|
||||
import React, { Fragment, Component } from 'react';
|
||||
import { Text, View, ScrollView, Alert } from 'react-native';
|
||||
import { Text, View, ScrollView, Alert, KeyboardAvoidingView, Platform } from 'react-native';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import Slider from '@esteemapp/react-native-slider';
|
||||
import get from 'lodash/get';
|
||||
|
||||
import { View as AnimatedView } from 'react-native-animatable';
|
||||
import { getWithdrawRoutes } from '../../../providers/hive/dhive';
|
||||
import AUTH_TYPE from '../../../constants/authType';
|
||||
|
||||
@ -18,16 +19,20 @@ import {
|
||||
InformationBox,
|
||||
Icon,
|
||||
IconButton,
|
||||
BeneficiarySelectionContent,
|
||||
TextInput,
|
||||
} from '../../../components';
|
||||
import WithdrawAccountModal from './withdrawAccountModal';
|
||||
|
||||
import parseToken from '../../../utils/parseToken';
|
||||
import parseDate from '../../../utils/parseDate';
|
||||
import { vestsToHp } from '../../../utils/conversions';
|
||||
import { isEmptyDate } from '../../../utils/time';
|
||||
import { hpToVests, vestsToHp } from '../../../utils/conversions';
|
||||
import { isEmptyDate, daysTillDate } from '../../../utils/time';
|
||||
|
||||
import styles from './transferStyles';
|
||||
import { OptionsModal } from '../../../components/atoms';
|
||||
import { Beneficiary } from '../../../redux/reducers/editorReducer';
|
||||
|
||||
/* Props
|
||||
* ------------------------------------------------
|
||||
* @prop { type } name - Description....
|
||||
@ -39,14 +44,18 @@ class PowerDownView extends Component {
|
||||
this.state = {
|
||||
from: props.currentAccountName,
|
||||
amount: 0,
|
||||
hp: 0.0,
|
||||
steemConnectTransfer: false,
|
||||
isTransfering: false,
|
||||
isOpenWithdrawAccount: false,
|
||||
destinationAccounts: [],
|
||||
disableDone: false,
|
||||
isAmountValid: false,
|
||||
};
|
||||
|
||||
this.startActionSheet = React.createRef();
|
||||
this.stopActionSheet = React.createRef();
|
||||
this.amountTextInput = React.createRef();
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
@ -86,6 +95,33 @@ class PowerDownView extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
_handleAmountChange = ({ hpValue, availableVestingShares }) => {
|
||||
const { hivePerMVests } = this.props;
|
||||
const parsedValue = parseFloat(hpValue);
|
||||
const vestsForHp = hpToVests(hpValue, hivePerMVests);
|
||||
const totalHP = vestsToHp(availableVestingShares, hivePerMVests).toFixed(3);
|
||||
|
||||
if (Number.isNaN(parsedValue)) {
|
||||
this.setState({ amount: 0, hp: 0.0, isAmountValid: false });
|
||||
} else if (parsedValue >= totalHP) {
|
||||
this.setState({
|
||||
amount: availableVestingShares,
|
||||
hp: totalHP,
|
||||
isAmountValid: false,
|
||||
});
|
||||
} else {
|
||||
this.setState({ amount: vestsForHp, hp: parsedValue, isAmountValid: true });
|
||||
}
|
||||
};
|
||||
|
||||
_handleSliderAmountChange = ({ value, availableVestingShares }) => {
|
||||
const { hivePerMVests } = this.props;
|
||||
const hp = vestsToHp(value, hivePerMVests).toFixed(3);
|
||||
const isAmountValid = value !== 0 && value <= availableVestingShares;
|
||||
this.setState({ amount: value, hp, isAmountValid });
|
||||
};
|
||||
|
||||
// renderers
|
||||
_renderDropdown = (accounts, currentAccountName) => (
|
||||
<DropdownButton
|
||||
dropdownButtonStyle={styles.dropdownButtonStyle}
|
||||
@ -155,6 +191,80 @@ class PowerDownView extends Component {
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
_renderBeneficiarySelectionContent = () => {
|
||||
const { intl } = this.props;
|
||||
const { from, destinationAccounts, amount } = this.state;
|
||||
|
||||
const powerDownBeneficiaries = destinationAccounts?.map((item) => ({
|
||||
account: item.username,
|
||||
weight: item.percent * 100,
|
||||
autoPowerUp: item.autoPowerUp,
|
||||
}));
|
||||
|
||||
const _handleSaveBeneficiary = (beneficiaries) => {
|
||||
const destinationAccounts = beneficiaries.map((item) => ({
|
||||
username: item.account,
|
||||
percent: item.weight / 100,
|
||||
autoPowerUp: item.autoPowerUp,
|
||||
}));
|
||||
let latestDestinationAccount = destinationAccounts[destinationAccounts.length - 1];
|
||||
if (latestDestinationAccount.username && latestDestinationAccount.percent) {
|
||||
this._handleOnSubmit(
|
||||
latestDestinationAccount.username,
|
||||
latestDestinationAccount.percent,
|
||||
latestDestinationAccount.autoPowerUp,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const _handleRemoveBeneficiary = (beneficiary) => {
|
||||
if (beneficiary) {
|
||||
const beneficiaryAccount = {
|
||||
username: beneficiary.account,
|
||||
percent: beneficiary.weight / 100,
|
||||
autoPowerUp: beneficiary.autoPowerUp,
|
||||
};
|
||||
this._removeDestinationAccount(beneficiaryAccount);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<View style={styles.beneficiaryContainer}>
|
||||
<BeneficiarySelectionContent
|
||||
label={intl.formatMessage({ id: 'transfer.withdraw_accounts' })}
|
||||
labelStyle={{ ...styles.sectionHeading, paddingLeft: 0 }}
|
||||
setDisableDone={this._handleSetDisableDone}
|
||||
powerDown={true}
|
||||
powerDownBeneficiaries={powerDownBeneficiaries}
|
||||
handleSaveBeneficiary={_handleSaveBeneficiary}
|
||||
handleRemoveBeneficiary={_handleRemoveBeneficiary}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
_renderAmountInput = (placeholder, availableVestingShares) => {
|
||||
const { isAmountValid } = this.state;
|
||||
return (
|
||||
<TextInput
|
||||
style={[styles.amountInput, !isAmountValid && styles.error]}
|
||||
onChangeText={(hpValue) => {
|
||||
this._handleAmountChange({ hpValue, availableVestingShares });
|
||||
}}
|
||||
value={this.state.hp}
|
||||
placeholder={placeholder}
|
||||
placeholderTextColor="#c1c5c7"
|
||||
autoCapitalize="none"
|
||||
multiline={false}
|
||||
keyboardType="decimal-pad"
|
||||
innerRef={this.amountTextInput}
|
||||
blurOnSubmit={false}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
_handleSetDisableDone = (value) => {
|
||||
this.setState({ disableDone: value });
|
||||
};
|
||||
_handleOnDropdownChange = (value) => {
|
||||
const { fetchBalance } = this.props;
|
||||
|
||||
@ -222,111 +332,127 @@ class PowerDownView extends Component {
|
||||
|
||||
const spCalculated = vestsToHp(amount, hivePerMVests);
|
||||
const fundPerWeek = Math.round((spCalculated / 13) * 1000) / 1000;
|
||||
const totalHP = vestsToHp(availableVestingShares, hivePerMVests);
|
||||
|
||||
const _renderSlider = () => (
|
||||
<View style={styles.sliderBox}>
|
||||
<View style={styles.emptyBox} />
|
||||
<View style={styles.sliderContainer}>
|
||||
<Slider
|
||||
style={styles.slider}
|
||||
trackStyle={styles.track}
|
||||
thumbStyle={styles.thumb}
|
||||
minimumTrackTintColor="#357ce6"
|
||||
thumbTintColor="#007ee5"
|
||||
maximumValue={availableVestingShares}
|
||||
value={amount}
|
||||
onValueChange={(value) =>
|
||||
this._handleSliderAmountChange({ value, availableVestingShares })
|
||||
}
|
||||
/>
|
||||
<View style={styles.sliderAmountContainer}>
|
||||
<Text style={styles.amountText}>{`MAX ${totalHP.toFixed(3)} HP`}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
const _renderMiddleContent = () => {
|
||||
const { intl } = this.props;
|
||||
return (
|
||||
<AnimatedView animation="bounceInRight" delay={500} useNativeDriver>
|
||||
<View style={styles.stepTwoContainer}>
|
||||
<Text style={styles.sectionHeading}>
|
||||
{intl.formatMessage({ id: 'transfer.power_down_amount_head' })}
|
||||
</Text>
|
||||
<View style={styles.alreadyDelegateRow}>
|
||||
<Text style={styles.sectionSubheading}>
|
||||
{intl.formatMessage({ id: 'transfer.power_down_amount_subhead' })}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<TransferFormItem
|
||||
label={intl.formatMessage({ id: 'transfer.amount_hp' })}
|
||||
rightComponent={() =>
|
||||
this._renderAmountInput(
|
||||
intl.formatMessage({ id: 'transfer.amount' }),
|
||||
availableVestingShares,
|
||||
)
|
||||
}
|
||||
containerStyle={styles.paddBottom}
|
||||
/>
|
||||
{_renderSlider()}
|
||||
<View style={styles.estimatedContainer}>
|
||||
<Text style={styles.leftEstimated} />
|
||||
<Text style={styles.rightEstimated}>
|
||||
{intl.formatMessage({ id: 'transfer.estimated_weekly' })} :
|
||||
{`+ ${fundPerWeek.toFixed(3)} HIVE`}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</AnimatedView>
|
||||
);
|
||||
};
|
||||
|
||||
const _renderPowerDownInfo = () => {
|
||||
const days = daysTillDate(nextPowerDown);
|
||||
return (
|
||||
<View style={styles.powerDownInfoContainer}>
|
||||
<Text style={styles.sectionHeading}>
|
||||
{intl.formatMessage({ id: 'transfer.powering_down' })}
|
||||
</Text>
|
||||
<Text style={styles.sectionSubheading}>
|
||||
{intl.formatMessage({ id: 'transfer.powering_down_subheading' }) +
|
||||
'\n\n' +
|
||||
intl.formatMessage(
|
||||
{ id: 'transfer.powering_down_info' },
|
||||
{ days: days, hp: poweringDownFund },
|
||||
)}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const _renderBottomContent = () => (
|
||||
<View style={styles.bottomContent}>
|
||||
{!poweringDown && (
|
||||
<Fragment>
|
||||
<MainButton
|
||||
style={styles.button}
|
||||
isDisable={amount <= 0}
|
||||
onPress={() => this.startActionSheet.current.show()}
|
||||
isLoading={isTransfering}
|
||||
>
|
||||
<Text style={styles.buttonText}>{intl.formatMessage({ id: 'transfer.next' })}</Text>
|
||||
</MainButton>
|
||||
</Fragment>
|
||||
)}
|
||||
{poweringDown && (
|
||||
<MainButton
|
||||
style={styles.stopButton}
|
||||
onPress={() => this.stopActionSheet.current.show()}
|
||||
isLoading={isTransfering}
|
||||
>
|
||||
<Text style={styles.buttonText}>{intl.formatMessage({ id: 'transfer.stop' })}</Text>
|
||||
</MainButton>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
return (
|
||||
<Fragment>
|
||||
<BasicHeader title={intl.formatMessage({ id: `transfer.${transferType}` })} />
|
||||
<View style={styles.container}>
|
||||
<ScrollView>
|
||||
<View style={styles.middleContent}>
|
||||
<TransferFormItem
|
||||
label={intl.formatMessage({ id: 'transfer.from' })}
|
||||
rightComponent={() => this._renderDropdown(accounts, currentAccountName)}
|
||||
/>
|
||||
<TransferFormItem
|
||||
label={intl.formatMessage({ id: 'transfer.destination_accounts' })}
|
||||
rightComponent={this._renderDestinationAccountItems}
|
||||
/>
|
||||
{!poweringDown && (
|
||||
<Fragment>
|
||||
<TransferFormItem
|
||||
label={intl.formatMessage({ id: 'transfer.amount' })}
|
||||
rightComponent={() => this._renderInformationText(`${amount.toFixed(6)} VESTS`)}
|
||||
/>
|
||||
<Slider
|
||||
style={styles.slider}
|
||||
trackStyle={styles.track}
|
||||
thumbStyle={styles.thumb}
|
||||
minimumTrackTintColor="#357ce6"
|
||||
thumbTintColor="#007ee5"
|
||||
maximumValue={availableVestingShares}
|
||||
value={amount}
|
||||
onValueChange={(value) => {
|
||||
this.setState({ amount: value });
|
||||
}}
|
||||
/>
|
||||
<Text style={styles.informationText}>
|
||||
{intl.formatMessage({ id: 'transfer.amount_information' })}
|
||||
</Text>
|
||||
</Fragment>
|
||||
)}
|
||||
{poweringDown && (
|
||||
<Fragment>
|
||||
<TransferFormItem
|
||||
label={intl.formatMessage({ id: 'transfer.incoming_funds' })}
|
||||
rightComponent={() =>
|
||||
this._renderIncomingFunds(
|
||||
poweringDownFund,
|
||||
poweringDownVests,
|
||||
nextPowerDown.toLocaleString(),
|
||||
)
|
||||
}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
</View>
|
||||
<View style={styles.bottomContent}>
|
||||
{!poweringDown && (
|
||||
<Fragment>
|
||||
<View style={styles.informationView}>
|
||||
<InformationBox
|
||||
style={styles.spInformation}
|
||||
text={`- ${spCalculated.toFixed(3)} HP`}
|
||||
/>
|
||||
<InformationBox
|
||||
style={styles.vestsInformation}
|
||||
text={`- ${amount.toFixed(0)} VESTS`}
|
||||
/>
|
||||
</View>
|
||||
<Icon
|
||||
style={styles.icon}
|
||||
size={40}
|
||||
iconType="MaterialIcons"
|
||||
name="arrow-downward"
|
||||
/>
|
||||
<InformationBox
|
||||
style={styles.steemInformation}
|
||||
text={`+ ${fundPerWeek.toFixed(3)} HIVE`}
|
||||
/>
|
||||
<Text style={styles.informationText}>
|
||||
{intl.formatMessage({ id: 'transfer.estimated_weekly' })}
|
||||
</Text>
|
||||
<MainButton
|
||||
style={styles.button}
|
||||
isDisable={amount <= 0}
|
||||
onPress={() => this.startActionSheet.current.show()}
|
||||
isLoading={isTransfering}
|
||||
>
|
||||
<Text style={styles.buttonText}>
|
||||
{intl.formatMessage({ id: 'transfer.next' })}
|
||||
</Text>
|
||||
</MainButton>
|
||||
</Fragment>
|
||||
)}
|
||||
{poweringDown && (
|
||||
<MainButton
|
||||
style={styles.stopButton}
|
||||
onPress={() => this.stopActionSheet.current.show()}
|
||||
isLoading={isTransfering}
|
||||
>
|
||||
<Text style={styles.buttonText}>
|
||||
{intl.formatMessage({ id: 'transfer.stop' })}
|
||||
</Text>
|
||||
</MainButton>
|
||||
)}
|
||||
</View>
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={styles.powerDownKeyboadrAvoidingContainer}
|
||||
keyboardShouldPersistTaps
|
||||
>
|
||||
<ScrollView style={styles.scroll} contentContainerStyle={styles.scrollContentContainer}>
|
||||
{!poweringDown && this._renderBeneficiarySelectionContent()}
|
||||
{!poweringDown && _renderMiddleContent()}
|
||||
{poweringDown && _renderPowerDownInfo()}
|
||||
{_renderBottomContent()}
|
||||
</ScrollView>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
<OptionsModal
|
||||
ref={this.startActionSheet}
|
||||
options={[
|
||||
|
@ -30,12 +30,11 @@ export default EStyleSheet.create({
|
||||
paddingVertical: 16,
|
||||
marginTop: 16,
|
||||
},
|
||||
scroll: {},
|
||||
middleContent: {
|
||||
flex: 3,
|
||||
justifyContent: 'center',
|
||||
flex: 1,
|
||||
},
|
||||
bottomContent: {
|
||||
flex: 2,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
@ -79,10 +78,12 @@ export default EStyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
fontWeight: 'bold',
|
||||
marginVertical: 16,
|
||||
},
|
||||
stopButton: {
|
||||
width: '$deviceWidth / 3',
|
||||
marginTop: 30,
|
||||
marginBottom: 30,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'red',
|
||||
@ -321,4 +322,41 @@ export default EStyleSheet.create({
|
||||
fullHeight: {
|
||||
height: '100%',
|
||||
},
|
||||
beneficiaryContainer: {
|
||||
paddingHorizontal: 12,
|
||||
zIndex: 2,
|
||||
borderRadius: 12,
|
||||
backgroundColor: '$primaryLightBackground',
|
||||
},
|
||||
scrollContentContainer: {
|
||||
flexGrow: 1,
|
||||
padding: 16,
|
||||
},
|
||||
estimatedContainer: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 12,
|
||||
},
|
||||
leftEstimated: {
|
||||
flex: 1,
|
||||
},
|
||||
rightEstimated: {
|
||||
flex: 2,
|
||||
fontSize: 12,
|
||||
color: '$primaryBlack',
|
||||
fontWeight: '600',
|
||||
textAlign: 'right',
|
||||
paddingRight: 16,
|
||||
},
|
||||
powerDownKeyboadrAvoidingContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
},
|
||||
powerDownInfoContainer: {
|
||||
marginTop: 16,
|
||||
paddingHorizontal: 12,
|
||||
zIndex: 2,
|
||||
paddingVertical: 16,
|
||||
borderRadius: 12,
|
||||
backgroundColor: '$primaryLightBackground',
|
||||
},
|
||||
});
|
||||
|
@ -134,3 +134,9 @@ export const isEmptyContentDate = (value) => {
|
||||
};
|
||||
|
||||
export const isEmptyDate = (s) => parseInt(s.split('-')[0], 10) < 1980;
|
||||
|
||||
export const daysTillDate = (date) => {
|
||||
var given = moment(new Date(date), 'YYYY-MM-DD');
|
||||
var current = moment().startOf('day');
|
||||
return Math.round(moment.duration(given.diff(current)).asDays());
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user