From 8015ff8895d4231b2fcb9cb62d5070bb8989021e Mon Sep 17 00:00:00 2001 From: Nouman Tahir Date: Mon, 7 Jun 2021 14:03:35 +0500 Subject: [PATCH] improved beneficiary input behaviour by using footer input --- .../beneficiaryModal/beneficiaryModal.tsx | 281 ++++++++++++------ .../beneficiaryModalStyles.ts | 12 +- .../formInput/view/formInputView.tsx | 21 +- 3 files changed, 208 insertions(+), 106 deletions(-) diff --git a/src/components/beneficiaryModal/beneficiaryModal.tsx b/src/components/beneficiaryModal/beneficiaryModal.tsx index cc158ef09..0e1f5c706 100644 --- a/src/components/beneficiaryModal/beneficiaryModal.tsx +++ b/src/components/beneficiaryModal/beneficiaryModal.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { View, FlatList, Text } from 'react-native'; +import { View, FlatList, Text, ScrollView } from 'react-native'; import { useIntl } from 'react-intl'; import AsyncStorage from '@react-native-community/async-storage'; import { isArray, debounce } from 'lodash'; @@ -10,6 +10,9 @@ import { FormInput, MainButton, Tag, TextButton } from '..'; import styles from './beneficiaryModalStyles'; import EStyleSheet from 'react-native-extended-stylesheet'; +import IconButton from '../iconButton'; +import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'; +import { iteratorStream } from '@esteemapp/dhive/lib/utils'; const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => { const intl = useIntl(); @@ -17,10 +20,12 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => { const [beneficiaries, setBeneficiaries] = useState([ { account: username, weight: 10000}, ]); - const [validity, setValidity] = useState([{ - weightValid:true, - usernameValid:true - }]) + + const [newUsername, setNewUsername] = useState(''); + const [newWeight, setNewWeight] = useState(0); + const [isUsernameValid, setIsUsernameValid] = useState(false); + const [isWeightValid, setIsWeightValid] = useState(false); + const [newEditable, setNewEditable] = useState(false); useEffect(() => { if (!isDraft) { @@ -28,6 +33,8 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => { } }, []); + + const readTempBeneficiaries = async () => { const tempBeneficiariesString = await AsyncStorage.getItem('temp-beneficiaries'); const tempBeneficiaries = JSON.parse(tempBeneficiariesString); @@ -41,96 +48,219 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => { } }; + + const _onSavePress = () => { + if(newEditable){ + beneficiaries.push({ + account:newUsername, + weight:newWeight + }) + } + handleOnSaveBeneficiaries(beneficiaries); + } + + const _addAccount = () => { - setBeneficiaries([...beneficiaries, { account: '', weight: 0}]); - setValidity([...validity, {weightValid:false, usernameValid:false}]) + + if(isUsernameValid && isWeightValid){ + beneficiaries.push({ + account:newUsername, + weight:newWeight, + }) + setBeneficiaries([...beneficiaries]); + } + + setIsUsernameValid(false); + setIsWeightValid(false); + setNewWeight(0); + setNewUsername(''); + setNewEditable(true); }; - const _onWeightInputChange = (value, index) => { + + + const _onWeightInputChange = (value) => { let _value = (parseInt(value, 10) || 0) * 100; - - const _diff = _value - beneficiaries[index].weight; + const _diff = _value - newWeight; beneficiaries[0].weight = beneficiaries[0].weight - _diff; - beneficiaries[index].weight = _value; - - validity[index].weightValid = _value > 0 && _value <= 10000; - - setBeneficiaries(beneficiaries); - setValidity([...validity]) + setNewWeight(_value) + setIsWeightValid(_value > 0 && _value <= 10000) + setBeneficiaries([...beneficiaries]); }; - const _lookupAccounts = debounce((username, index)=>{ + + const _lookupAccounts = debounce((username) => { + lookupAccounts(username).then((res) => { - const isValid = - res.includes(username) - validity[index].usernameValid = isValid; - setValidity([...validity]); + 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) }); - }, 500) + }, 1000) - const _onUsernameInputChange = (value, index) => { - _lookupAccounts(value, index); - beneficiaries[index].account = value; - setBeneficiaries(beneficiaries); + + const _onUsernameInputChange = (value) => { + setNewUsername(value); + _lookupAccounts(value); }; + + const _isValid = () => { - return validity.every((item) => (item.usernameValid && item.weightValid)); + return !newEditable || (isUsernameValid && isWeightValid); }; - const _onBlur = (item) => { - if (item.weight === 0) { - const newBeneficiaries = [...beneficiaries]; - const newValidity = [...validity]; - const index = newBeneficiaries.findIndex((current)=>current.account === item.account); - if(index >= 0){ - newBeneficiaries.splice(index, 1); - newValidity.splice(index, 1); + + const _renderHeader = () => ( + + + + {intl.formatMessage({ + id: 'beneficiary_modal.percent', + })} + + + + + {intl.formatMessage({ + id: 'beneficiary_modal.username', + })} + + + + ) + + + const _renderInput = () => { + + const _onCancelPress = () => { + if(newWeight){ + beneficiaries[0].weight = beneficiaries[0].weight + newWeight; + setBeneficiaries([...beneficiaries]) + setNewWeight(0); } - - setBeneficiaries(newBeneficiaries); - setValidity(newValidity); + setNewEditable(false); + setIsWeightValid(false); + setIsUsernameValid(false); + setNewUsername(''); + } - }; - - - const renderInput = ({ item, index }) => { - const _isCurrentUser = item.account === username; - const {weightValid, usernameValid} = validity[index]; return ( _onWeightInputChange(value, index)} - onBlur={() => _onBlur(item)} + onChange={(value) => _onWeightInputChange(value)} + onBlur={() => {}}//_onBlur(item)} keyboardType='numeric' /> + _onUsernameInputChange(value, index)} + isValid={isUsernameValid} + onChange={(value) => _onUsernameInputChange(value)} placeholder={intl.formatMessage({ id: 'beneficiary_modal.username', })} type="username" isFirstImage + value={newUsername} + inputStyle={styles.usernameInput} + wrapperStyle={styles.usernameFormInputWrapper} + /> + + + + + + ); + }; + + + 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]); + } + + + return ( + + + + + + + + {!_isCurrentUser ? ( + + ):( + + )} + ); }; @@ -140,51 +270,22 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => { return ( - + + ( - - - - {intl.formatMessage({ - id: 'beneficiary_modal.percent', - })} - - - - - {intl.formatMessage({ - id: 'beneficiary_modal.username', - })} - - - - )} - ListFooterComponent={() => ( - - - - )} + renderItem={_renderItem} + ListHeaderComponent={_renderHeader} + showsVerticalScrollIndicator={false} /> - + {_renderFooter()} + + handleOnSaveBeneficiaries(beneficiaries)} + onPress={_onSavePress} text={intl.formatMessage({ id: 'beneficiary_modal.save', })} diff --git a/src/components/beneficiaryModal/beneficiaryModalStyles.ts b/src/components/beneficiaryModal/beneficiaryModalStyles.ts index 4cacabf76..b55d89f9e 100644 --- a/src/components/beneficiaryModal/beneficiaryModalStyles.ts +++ b/src/components/beneficiaryModal/beneficiaryModalStyles.ts @@ -3,19 +3,19 @@ import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ container: { flex: 1, + padding:16, justifyContent: 'space-between', - padding: 16, backgroundColor:'$modalBackground', }, - bodyWrapper: { flex: 3, paddingTop: 20 }, + bodyWrapper: { flex: 1, paddingTop: 20, paddingBottom:20}, inputWrapper: { flexDirection: 'row', alignItems: 'center' }, text: { color: '$primaryBlack', marginBottom: 8 }, - weightInput: { flex: 1 }, + weightInput: {width:80}, weightFormInput: { textAlign: 'center', color: '$primaryBlack' }, weightFormInputWrapper: { marginTop: 8 }, - usernameInput: { flex: 3, color: '$primaryBlack', marginLeft: 16 }, - usernameFormInputWrapper: { marginTop: 8, marginLeft: 10 }, - footerWrapper: { paddingTop:16, paddingBottom:16 }, + usernameInput: { flex:1, color: '$primaryBlack', marginLeft: 16 }, + usernameFormInputWrapper: { marginTop: 8 }, + footerWrapper: { paddingTop:16 }, saveButton: { width: 140, height: 44, diff --git a/src/components/formInput/view/formInputView.tsx b/src/components/formInput/view/formInputView.tsx index 8118aa8be..13c0df211 100644 --- a/src/components/formInput/view/formInputView.tsx +++ b/src/components/formInput/view/formInputView.tsx @@ -15,16 +15,17 @@ import styles from './formInputStyles'; interface Props extends TextInputProps { - type:string, - isFirstImage:boolean, - isEditable?:boolean, - leftIconName?:string, - rightIconName?:string, - iconType?:string, - wrapperStyle:ViewStyle, - height:number, - inputStyle:TextStyle, - isValid:boolean + type:string; + isFirstImage:boolean; + isEditable?:boolean; + leftIconName?:string; + rightIconName?:string; + iconType?:string; + wrapperStyle:ViewStyle; + height:number; + inputStyle:TextStyle; + isValid:boolean; + onChange?:(value:string)=>void; } const FormInputView = ({