From eccda2af254552d87bbaf4b7330ff9054adb2ecd Mon Sep 17 00:00:00 2001 From: Sadaqat Ali Date: Sun, 17 Apr 2022 13:58:58 +0500 Subject: [PATCH] integrated beneficiary selection module in powerdown screen --- .../beneficiarySelectionContent.tsx | 351 ++++++++++++++++++ .../beneficiarySelectionContent/styles.ts | 59 +++ src/components/index.js | 2 + src/redux/constants/constants.js | 1 - src/redux/reducers/editorReducer.ts | 1 + .../children/beneficiarySelectionContent.tsx | 14 +- .../transfer/screen/powerDownScreen.js | 52 ++- src/screens/transfer/screen/transferStyles.js | 9 +- 8 files changed, 468 insertions(+), 21 deletions(-) create mode 100644 src/components/beneficiarySelectionContent/beneficiarySelectionContent.tsx create mode 100644 src/components/beneficiarySelectionContent/styles.ts diff --git a/src/components/beneficiarySelectionContent/beneficiarySelectionContent.tsx b/src/components/beneficiarySelectionContent/beneficiarySelectionContent.tsx new file mode 100644 index 000000000..3cdd6f8a1 --- /dev/null +++ b/src/components/beneficiarySelectionContent/beneficiarySelectionContent.tsx @@ -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( + [{ 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 = () => ( + + + + {intl.formatMessage({ + id: 'beneficiary_modal.percent', + })} + + + + + {intl.formatMessage({ + id: 'beneficiary_modal.username', + })} + + + + ) + + + + const _renderInput = () => { + + return ( + + + _onWeightInputChange(value)} + selectTextOnFocus={true} + autoFocus={true} + returnKeyType={'next'} + keyboardType='numeric' + /> + + + + _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} + /> + + + {isWeightValid && isUsernameValid ? ( + + ) : } + + + ); + }; + + + const _renderFooter = () => ( + <> + {newEditable && _renderInput()} + + + + + + + ) + + + 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 ( + + + + + + + + + {!_isCurrentUser ? ( + + ):( + + )} + + + ); + }; + + return ( + + {intl.formatMessage({id:'editor.beneficiaries'})} + + {_renderFooter()} + + ); +}; + +export default BeneficiarySelectionContent; diff --git a/src/components/beneficiarySelectionContent/styles.ts b/src/components/beneficiarySelectionContent/styles.ts new file mode 100644 index 000000000..1ca481ad5 --- /dev/null +++ b/src/components/beneficiarySelectionContent/styles.ts @@ -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, + }, + +}); diff --git a/src/components/index.js b/src/components/index.js index d0527eb46..66916992a 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -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, }; diff --git a/src/redux/constants/constants.js b/src/redux/constants/constants.js index 3f8ced7e8..54a07ebaa 100644 --- a/src/redux/constants/constants.js +++ b/src/redux/constants/constants.js @@ -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'; diff --git a/src/redux/reducers/editorReducer.ts b/src/redux/reducers/editorReducer.ts index b6dca08ac..4323791ca 100644 --- a/src/redux/reducers/editorReducer.ts +++ b/src/redux/reducers/editorReducer.ts @@ -4,6 +4,7 @@ export interface Beneficiary { account:string, weight:number, isValid?:boolean, + autoPowerUp?: boolean, } interface State { diff --git a/src/screens/editor/children/beneficiarySelectionContent.tsx b/src/screens/editor/children/beneficiarySelectionContent.tsx index c54f241a1..03a76486a 100644 --- a/src/screens/editor/children/beneficiarySelectionContent.tsx +++ b/src/screens/editor/children/beneficiarySelectionContent.tsx @@ -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)); } diff --git a/src/screens/transfer/screen/powerDownScreen.js b/src/screens/transfer/screen/powerDownScreen.js index eeedfae29..d8b9ff5d0 100644 --- a/src/screens/transfer/screen/powerDownScreen.js +++ b/src/screens/transfer/screen/powerDownScreen.js @@ -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 { ); - _renderBeneficiarySelectionContent = () => ( - - ); + _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 ( + + + + ); + }; _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 ( - + {this._renderBeneficiarySelectionContent()} - this._renderDropdown(accounts, currentAccountName)} /> + /> */} {!poweringDown && (