Merge pull request #2269 from ecency/sa/power-down-screen

[WIP] Redesign Power Down Screen
This commit is contained in:
Feruz M 2022-04-21 07:04:50 +03:00 committed by GitHub
commit d0b1dedfe5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 736 additions and 111 deletions

View File

@ -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;

View 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,
}
});

View File

@ -15,7 +15,7 @@ export default EStyleSheet.create({
height: 24, height: 24,
borderRadius: 12, borderRadius: 12,
top: 15, top: 15,
marginLeft: 12, marginLeft: 8,
}, },
textInput: { textInput: {
flex: 1, flex: 1,

View File

@ -101,7 +101,7 @@ const FormInputView = ({
]} ]}
> >
{isFirstImage && value && value.length > 2 ? ( {isFirstImage && value && value.length > 2 ? (
<View style={{ flex: 0.15 }}> <View style={{ flex: 0.2 }}>
<FastImage <FastImage
style={styles.firstImage} style={styles.firstImage}
source={{ source={{

View File

@ -97,6 +97,7 @@ import Tooltip from './tooltip/tooltipView';
import VideoPlayer from './videoPlayer/videoPlayerView'; import VideoPlayer from './videoPlayer/videoPlayerView';
import QRModal from './qrModal/qrModalView'; import QRModal from './qrModal/qrModalView';
import { SimpleChart } from './simpleChart'; import { SimpleChart } from './simpleChart';
import BeneficiarySelectionContent from './beneficiarySelectionContent/beneficiarySelectionContent';
// Basic UI Elements // Basic UI Elements
import { import {
@ -243,4 +244,5 @@ export {
InsertLinkModal, InsertLinkModal,
QRModal, QRModal,
SimpleChart, SimpleChart,
BeneficiarySelectionContent,
}; };

View File

@ -576,11 +576,11 @@
"stop_information": "Are you sure want to stop?", "stop_information": "Are you sure want to stop?",
"percent": "Percent", "percent": "Percent",
"auto_vests": "Auto Vests", "auto_vests": "Auto Vests",
"vests": "Vests",
"save": "SAVE", "save": "SAVE",
"percent_information": "Percent info", "percent_information": "Percent info",
"next": "NEXT", "next": "NEXT",
"delegate": "Delegate", "delegate": "Delegate",
"power_down": "Power Down",
"withdraw_hive": "Withdraw HIVE", "withdraw_hive": "Withdraw HIVE",
"withdraw_hbd": "Withdraw HIVE Dollar", "withdraw_hbd": "Withdraw HIVE Dollar",
"incoming_funds": "Incoming Funds", "incoming_funds": "Incoming Funds",
@ -599,7 +599,16 @@
"confirm_summary": "Delegate {hp} HP ({vests} VESTS) To @{delegator} from @{delegatee} ", "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.", "confirm_summary_para": "This will overwrite your previous delegation of {prev} HP to this user.",
"username_alert": "Username Error!", "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": { "boost": {
"title": "Get Points", "title": "Get Points",

View File

@ -4,6 +4,7 @@ export interface Beneficiary {
account:string, account:string,
weight:number, weight:number,
isValid?:boolean, isValid?:boolean,
autoPowerUp?: boolean,
} }
interface State { interface State {

View File

@ -18,7 +18,7 @@ interface BeneficiarySelectionContent {
setDisableDone:(value:boolean)=>void; setDisableDone:(value:boolean)=>void;
} }
const BeneficiarySelectionContent = ({ draftId, setDisableDone }) => { const BeneficiarySelectionContent = ({ draftId, setDisableDone}) => {
const intl = useIntl(); const intl = useIntl();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -35,6 +35,7 @@ const BeneficiarySelectionContent = ({ draftId, setDisableDone }) => {
const [isWeightValid, setIsWeightValid] = useState(false); const [isWeightValid, setIsWeightValid] = useState(false);
const [newEditable, setNewEditable] = useState(false); const [newEditable, setNewEditable] = useState(false);
useEffect(() => { useEffect(() => {
readTempBeneficiaries(); readTempBeneficiaries();
}, [draftId]); }, [draftId]);

View File

@ -1,10 +1,11 @@
/* eslint-disable react/no-unused-state */ /* eslint-disable react/no-unused-state */
import React, { Fragment, Component } from 'react'; 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 { injectIntl } from 'react-intl';
import Slider from '@esteemapp/react-native-slider'; import Slider from '@esteemapp/react-native-slider';
import get from 'lodash/get'; import get from 'lodash/get';
import { View as AnimatedView } from 'react-native-animatable';
import { getWithdrawRoutes } from '../../../providers/hive/dhive'; import { getWithdrawRoutes } from '../../../providers/hive/dhive';
import AUTH_TYPE from '../../../constants/authType'; import AUTH_TYPE from '../../../constants/authType';
@ -18,16 +19,20 @@ import {
InformationBox, InformationBox,
Icon, Icon,
IconButton, IconButton,
BeneficiarySelectionContent,
TextInput,
} from '../../../components'; } from '../../../components';
import WithdrawAccountModal from './withdrawAccountModal'; import WithdrawAccountModal from './withdrawAccountModal';
import parseToken from '../../../utils/parseToken'; import parseToken from '../../../utils/parseToken';
import parseDate from '../../../utils/parseDate'; import parseDate from '../../../utils/parseDate';
import { vestsToHp } from '../../../utils/conversions'; import { hpToVests, vestsToHp } from '../../../utils/conversions';
import { isEmptyDate } from '../../../utils/time'; import { isEmptyDate, daysTillDate } from '../../../utils/time';
import styles from './transferStyles'; import styles from './transferStyles';
import { OptionsModal } from '../../../components/atoms'; import { OptionsModal } from '../../../components/atoms';
import { Beneficiary } from '../../../redux/reducers/editorReducer';
/* Props /* Props
* ------------------------------------------------ * ------------------------------------------------
* @prop { type } name - Description.... * @prop { type } name - Description....
@ -39,14 +44,18 @@ class PowerDownView extends Component {
this.state = { this.state = {
from: props.currentAccountName, from: props.currentAccountName,
amount: 0, amount: 0,
hp: 0.0,
steemConnectTransfer: false, steemConnectTransfer: false,
isTransfering: false, isTransfering: false,
isOpenWithdrawAccount: false, isOpenWithdrawAccount: false,
destinationAccounts: [], destinationAccounts: [],
disableDone: false,
isAmountValid: false,
}; };
this.startActionSheet = React.createRef(); this.startActionSheet = React.createRef();
this.stopActionSheet = React.createRef(); this.stopActionSheet = React.createRef();
this.amountTextInput = React.createRef();
} }
// Component Functions // 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) => ( _renderDropdown = (accounts, currentAccountName) => (
<DropdownButton <DropdownButton
dropdownButtonStyle={styles.dropdownButtonStyle} dropdownButtonStyle={styles.dropdownButtonStyle}
@ -155,6 +191,80 @@ class PowerDownView extends Component {
</Fragment> </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) => { _handleOnDropdownChange = (value) => {
const { fetchBalance } = this.props; const { fetchBalance } = this.props;
@ -222,27 +332,12 @@ class PowerDownView extends Component {
const spCalculated = vestsToHp(amount, hivePerMVests); const spCalculated = vestsToHp(amount, hivePerMVests);
const fundPerWeek = Math.round((spCalculated / 13) * 1000) / 1000; const fundPerWeek = Math.round((spCalculated / 13) * 1000) / 1000;
const totalHP = vestsToHp(availableVestingShares, hivePerMVests);
return ( const _renderSlider = () => (
<Fragment> <View style={styles.sliderBox}>
<BasicHeader title={intl.formatMessage({ id: `transfer.${transferType}` })} /> <View style={styles.emptyBox} />
<View style={styles.container}> <View style={styles.sliderContainer}>
<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 <Slider
style={styles.slider} style={styles.slider}
trackStyle={styles.track} trackStyle={styles.track}
@ -251,65 +346,84 @@ class PowerDownView extends Component {
thumbTintColor="#007ee5" thumbTintColor="#007ee5"
maximumValue={availableVestingShares} maximumValue={availableVestingShares}
value={amount} value={amount}
onValueChange={(value) => { onValueChange={(value) =>
this.setState({ amount: value }); this._handleSliderAmountChange({ value, availableVestingShares })
}}
/>
<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 style={styles.sliderAmountContainer}>
)} <Text style={styles.amountText}>{`MAX ${totalHP.toFixed(3)} HP`}</Text>
</View> </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}> <View style={styles.bottomContent}>
{!poweringDown && ( {!poweringDown && (
<Fragment> <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 <MainButton
style={styles.button} style={styles.button}
isDisable={amount <= 0} isDisable={amount <= 0}
onPress={() => this.startActionSheet.current.show()} onPress={() => this.startActionSheet.current.show()}
isLoading={isTransfering} isLoading={isTransfering}
> >
<Text style={styles.buttonText}> <Text style={styles.buttonText}>{intl.formatMessage({ id: 'transfer.next' })}</Text>
{intl.formatMessage({ id: 'transfer.next' })}
</Text>
</MainButton> </MainButton>
</Fragment> </Fragment>
)} )}
@ -319,14 +433,26 @@ class PowerDownView extends Component {
onPress={() => this.stopActionSheet.current.show()} onPress={() => this.stopActionSheet.current.show()}
isLoading={isTransfering} isLoading={isTransfering}
> >
<Text style={styles.buttonText}> <Text style={styles.buttonText}>{intl.formatMessage({ id: 'transfer.stop' })}</Text>
{intl.formatMessage({ id: 'transfer.stop' })}
</Text>
</MainButton> </MainButton>
)} )}
</View> </View>
);
return (
<Fragment>
<BasicHeader title={intl.formatMessage({ id: `transfer.${transferType}` })} />
<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> </ScrollView>
</View> </KeyboardAvoidingView>
<OptionsModal <OptionsModal
ref={this.startActionSheet} ref={this.startActionSheet}
options={[ options={[

View File

@ -30,12 +30,11 @@ export default EStyleSheet.create({
paddingVertical: 16, paddingVertical: 16,
marginTop: 16, marginTop: 16,
}, },
scroll: {},
middleContent: { middleContent: {
flex: 3, flex: 1,
justifyContent: 'center',
}, },
bottomContent: { bottomContent: {
flex: 2,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
}, },
@ -79,10 +78,12 @@ export default EStyleSheet.create({
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
fontWeight: 'bold', fontWeight: 'bold',
marginVertical: 16,
}, },
stopButton: { stopButton: {
width: '$deviceWidth / 3', width: '$deviceWidth / 3',
marginTop: 30, marginTop: 30,
marginBottom: 30,
justifyContent: 'center', justifyContent: 'center',
alignItems: 'center', alignItems: 'center',
backgroundColor: 'red', backgroundColor: 'red',
@ -321,4 +322,41 @@ export default EStyleSheet.create({
fullHeight: { fullHeight: {
height: '100%', 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',
},
}); });

View File

@ -134,3 +134,9 @@ export const isEmptyContentDate = (value) => {
}; };
export const isEmptyDate = (s) => parseInt(s.split('-')[0], 10) < 1980; 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());
};