improved beneficiary input behaviour by using footer input

This commit is contained in:
Nouman Tahir 2021-06-07 14:03:35 +05:00
parent c6208d4cf4
commit 8015ff8895
3 changed files with 208 additions and 106 deletions

View File

@ -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,111 +48,73 @@ 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));
};
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);
}
setBeneficiaries(newBeneficiaries);
setValidity(newValidity);
}
return !newEditable || (isUsernameValid && isWeightValid);
};
const renderInput = ({ item, index }) => {
const _isCurrentUser = item.account === username;
const {weightValid, usernameValid} = validity[index];
return (
<View style={styles.inputWrapper}>
<View style={styles.weightInput}>
<FormInput
isValid={_isCurrentUser || weightValid}
isEditable={!_isCurrentUser}
value={`${item.weight / 100}`}
inputStyle={styles.weightFormInput}
wrapperStyle={styles.weightFormInputWrapper}
onChange={(value) => _onWeightInputChange(value, index)}
onBlur={() => _onBlur(item)}
keyboardType='numeric'
/>
</View>
<View style={styles.usernameInput}>
<FormInput
rightIconName="at"
iconType="MaterialCommunityIcons"
isValid={_isCurrentUser || usernameValid}
//isEditable={!_isCurrentUser}
onChange={(value) => _onUsernameInputChange(value, index)}
placeholder={intl.formatMessage({
id: 'beneficiary_modal.username',
})}
type="username"
isFirstImage
value={item.account}
inputStyle={styles.usernameInput}
wrapperStyle={styles.usernameFormInputWrapper}
/>
</View>
</View>
);
};
const isAllValid = _isValid();
return (
<View style={styles.container}>
<View style={styles.bodyWrapper}>
<FlatList
data={beneficiaries}
renderItem={renderInput}
extraData={validity}
ListHeaderComponent={() => (
const _renderHeader = () => (
<View style={styles.inputWrapper}>
<View style={[styles.weightInput, { alignItems: 'center' }]}>
<Text style={styles.text}>
@ -162,9 +131,73 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => {
</Text>
</View>
</View>
)}
ListFooterComponent={() => (
<View style={{marginTop: 20 }}>
)
const _renderInput = () => {
const _onCancelPress = () => {
if(newWeight){
beneficiaries[0].weight = beneficiaries[0].weight + newWeight;
setBeneficiaries([...beneficiaries])
setNewWeight(0);
}
setNewEditable(false);
setIsWeightValid(false);
setIsUsernameValid(false);
setNewUsername('');
}
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)}
onBlur={() => {}}//_onBlur(item)}
keyboardType='numeric'
/>
</View>
<View style={styles.usernameInput}>
<FormInput
rightIconName="at"
iconType="MaterialCommunityIcons"
isValid={isUsernameValid}
onChange={(value) => _onUsernameInputChange(value)}
placeholder={intl.formatMessage({
id: 'beneficiary_modal.username',
})}
type="username"
isFirstImage
value={newUsername}
inputStyle={styles.usernameInput}
wrapperStyle={styles.usernameFormInputWrapper}
/>
</View>
<IconButton
name="close"
iconType="MaterialCommunityIcons"
color={EStyleSheet.value('$primaryBlack')}
size={24}
iconStyle={{paddingLeft:8}}
onPress={_onCancelPress}
/>
</View>
);
};
const _renderFooter = () => (
<>
{newEditable && _renderInput()}
<View style={{marginTop: 20, marginBottom:32 }}>
<TextButton
text={intl.formatMessage({
id: 'beneficiary_modal.addAccount',
@ -177,14 +210,82 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => {
}}
/>
</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]);
}
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>
);
};
const isAllValid = _isValid();
return (
<View style={styles.container}>
<KeyboardAwareScrollView style={styles.bodyWrapper}>
<FlatList
data={beneficiaries}
renderItem={_renderItem}
ListHeaderComponent={_renderHeader}
showsVerticalScrollIndicator={false}
/>
{_renderFooter()}
</KeyboardAwareScrollView>
<View style={styles.footerWrapper}>
<MainButton
style={styles.saveButton}
isDisable={!_isValid()}
onPress={() => handleOnSaveBeneficiaries(beneficiaries)}
onPress={_onSavePress}
text={intl.formatMessage({
id: 'beneficiary_modal.save',
})}

View File

@ -3,19 +3,19 @@ import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
container: {
flex: 1,
justifyContent: 'space-between',
padding:16,
justifyContent: 'space-between',
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,

View File

@ -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 = ({