integrated beneficiary selection module in powerdown screen

This commit is contained in:
Sadaqat Ali 2022-04-17 13:58:58 +05:00
parent 25c241b556
commit eccda2af25
8 changed files with 468 additions and 21 deletions

View File

@ -0,0 +1,351 @@
import React, { useState, useEffect } from 'react';
import { View, FlatList, Text } 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, 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;
powerDownBeneficiaries?: Beneficiary[];
handleSaveBeneficiary?:(beneficiaries: Beneficiary[]) => void;
}
const BeneficiarySelectionContent = ({ draftId, setDisableDone, powerDown, powerDownBeneficiaries, handleSaveBeneficiary }: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])
console.log('beneficiaries : ', beneficiaries);
const readPowerDownBeneficiaries = () => {
const tempBeneficiaries = [{ account: username, weight: 10000, autoPowerUp: false}, ...powerDownBeneficiaries]
console.log('tempBeneficiaries in readPowerDownBeneficiaries: ', tempBeneficiaries);
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}>
<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 _renderInput = () => {
return (
<View style={styles.inputWrapper}>
<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;
beneficiaries.splice(index, 1);
setBeneficiaries([...beneficiaries]);
_saveBeneficiaries(beneficiaries);
}
return (
<View style={styles.inputWrapper}>
<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={styles.settingLabel}>{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,59 @@
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,
},
});

View File

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

View File

@ -105,7 +105,6 @@ export const SET_OWN_PROFILE_TABS = 'SET_OWN_PROFILE_TABS';
export const SET_BENEFICIARIES = 'SET_BENEFICIARIES';
export const REMOVE_BENEFICIARIES = 'REMOVE_BENEFICIARIES';
export const TEMP_BENEFICIARIES_ID = 'temp-beneficiaries';
export const POWER_DOWN_BENEFICIARIES_ID = 'power-down-beneficiaries';
//CACHE
export const PURGE_EXPIRED_CACHE = 'PURGE_EXPIRED_CACHE';

View File

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

View File

@ -10,16 +10,15 @@ import { useAppDispatch, useAppSelector } from '../../../hooks';
import { BeneficiaryModal, FormInput, IconButton, TextButton } from '../../../components';
import { Beneficiary } from '../../../redux/reducers/editorReducer';
import { lookupAccounts } from '../../../providers/hive/dhive';
import { TEMP_BENEFICIARIES_ID, POWER_DOWN_BENEFICIARIES_ID } from '../../../redux/constants/constants';
import { TEMP_BENEFICIARIES_ID } from '../../../redux/constants/constants';
import { removeBeneficiaries, setBeneficiaries as setBeneficiariesAction } from '../../../redux/actions/editorActions';
interface BeneficiarySelectionContent {
draftId:string;
setDisableDone:(value:boolean)=>void;
powerDown?: boolean;
}
const BeneficiarySelectionContent = ({ draftId, setDisableDone, powerDown }) => {
const BeneficiarySelectionContent = ({ draftId, setDisableDone}) => {
const intl = useIntl();
const dispatch = useAppDispatch();
@ -36,11 +35,6 @@ const BeneficiarySelectionContent = ({ draftId, setDisableDone, powerDown }) =>
const [isWeightValid, setIsWeightValid] = useState(false);
const [newEditable, setNewEditable] = useState(false);
useEffect(() => {
if(powerDown){
readTempBeneficiaries();
}
},[]);
useEffect(() => {
readTempBeneficiaries();
@ -53,7 +47,7 @@ const BeneficiarySelectionContent = ({ draftId, setDisableDone, powerDown }) =>
const readTempBeneficiaries = async () => {
if(beneficiariesMap){
const tempBeneficiaries = beneficiariesMap[powerDown ? POWER_DOWN_BENEFICIARIES_ID : draftId || TEMP_BENEFICIARIES_ID];
const tempBeneficiaries = beneficiariesMap[draftId || TEMP_BENEFICIARIES_ID];
if (isArray(tempBeneficiaries) && tempBeneficiaries.length > 0) {
@ -73,7 +67,7 @@ const BeneficiarySelectionContent = ({ draftId, setDisableDone, powerDown }) =>
const _saveBeneficiaries = (value:Beneficiary[]) => {
dispatch(setBeneficiariesAction(powerDown ? POWER_DOWN_BENEFICIARIES_ID : draftId || TEMP_BENEFICIARIES_ID, value));
dispatch(setBeneficiariesAction(draftId || TEMP_BENEFICIARIES_ID, value));
}

View File

@ -18,6 +18,7 @@ import {
InformationBox,
Icon,
IconButton,
BeneficiarySelectionContent,
} from '../../../components';
import WithdrawAccountModal from './withdrawAccountModal';
@ -28,7 +29,8 @@ import { isEmptyDate } from '../../../utils/time';
import styles from './transferStyles';
import { OptionsModal } from '../../../components/atoms';
import BeneficiarySelectionContent from '../../editor/children/beneficiarySelectionContent';
import { Beneficiary } from '../../../redux/reducers/editorReducer';
/* Props
* ------------------------------------------------
* @prop { type } name - Description....
@ -157,9 +159,43 @@ class PowerDownView extends Component {
</Fragment>
);
_renderBeneficiarySelectionContent = () => (
<BeneficiarySelectionContent setDisableDone={this._handleSetDisableDone} powerDown={true} />
);
_renderBeneficiarySelectionContent = () => {
const { from, destinationAccounts, amount } = this.state;
const powerDownBeneficiaries = destinationAccounts?.map((item) => ({
account: item.username,
weight: item.percent * 100,
autoPowerUp: item.autoPowerUp,
}));
const _handleSaveBeneficiary = (beneficiaries) => {
console.log('beneficiaries in _handleSaveBeneficiary: ', beneficiaries);
const destinationAccounts = beneficiaries.map((item) => ({
username: item.account,
percent: item.weight / 100,
autoPowerUp: item.autoPowerUp,
}));
console.log('destinationAccounts in _handleSaveBeneficiary :', destinationAccounts);
let latestDestinationAccount = destinationAccounts[destinationAccounts.length - 1];
console.log('latestDestinationAccount : ', latestDestinationAccount);
if (latestDestinationAccount.username && latestDestinationAccount.percent) {
this._handleOnSubmit(
latestDestinationAccount.username,
latestDestinationAccount.percent,
latestDestinationAccount.autoPowerUp,
);
}
};
return (
<View style={styles.beneficiaryContainer}>
<BeneficiarySelectionContent
setDisableDone={this._handleSetDisableDone}
powerDown={true}
powerDownBeneficiaries={powerDownBeneficiaries}
handleSaveBeneficiary={_handleSaveBeneficiary}
/>
</View>
);
};
_handleSetDisableDone = (value) => {
this.setState({ disableDone: value });
@ -232,21 +268,23 @@ class PowerDownView extends Component {
const spCalculated = vestsToHp(amount, hivePerMVests);
const fundPerWeek = Math.round((spCalculated / 13) * 1000) / 1000;
console.log('this.state : ', this.state);
return (
<Fragment>
<BasicHeader title={intl.formatMessage({ id: `transfer.${transferType}` })} />
<View style={styles.container}>
<ScrollView>
<ScrollView style={styles.scroll} contentContainerStyle={{ flexGrow: 1 }}>
{this._renderBeneficiarySelectionContent()}
<View style={styles.middleContent}>
<TransferFormItem
{/* <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

View File

@ -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',
},
@ -83,6 +82,7 @@ export default EStyleSheet.create({
stopButton: {
width: '$deviceWidth / 3',
marginTop: 30,
marginBottom: 30,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'red',
@ -321,4 +321,7 @@ export default EStyleSheet.create({
fullHeight: {
height: '100%',
},
beneficiaryContainer: {
paddingHorizontal: 12,
},
});