mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-18 19:01:38 +03:00
improved beneficiary modal
1. manage validity state separate 2. 500 ms debounce for account check 3. tweak UI for better presentation
This commit is contained in:
parent
fa77aa48a2
commit
18016e604d
@ -1,21 +1,26 @@
|
|||||||
import React, { useState, useCallback, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { View, FlatList, Text } from 'react-native';
|
import { View, FlatList, Text } from 'react-native';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
import AsyncStorage from '@react-native-community/async-storage';
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
import { isArray, remove } from 'lodash';
|
import { isArray, debounce } from 'lodash';
|
||||||
|
|
||||||
import { lookupAccounts } from '../../providers/hive/dhive';
|
import { lookupAccounts } from '../../providers/hive/dhive';
|
||||||
|
|
||||||
import { FormInput, MainButton, Tag } from '..';
|
import { FormInput, MainButton, Tag, TextButton } from '..';
|
||||||
|
|
||||||
import styles from './beneficiaryModalStyles';
|
import styles from './beneficiaryModalStyles';
|
||||||
|
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||||
|
|
||||||
const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => {
|
const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const [beneficiaries, setBeneficiaries] = useState([
|
const [beneficiaries, setBeneficiaries] = useState([
|
||||||
{ account: username, weight: 10000, isValid: true },
|
{ account: username, weight: 10000},
|
||||||
]);
|
]);
|
||||||
|
const [validity, setValidity] = useState([{
|
||||||
|
weightValid:true,
|
||||||
|
usernameValid:true
|
||||||
|
}])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isDraft) {
|
if (!isDraft) {
|
||||||
@ -37,7 +42,8 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const _addAccount = () => {
|
const _addAccount = () => {
|
||||||
setBeneficiaries([...beneficiaries, { account: '', weight: 0, isValid: false }]);
|
setBeneficiaries([...beneficiaries, { account: '', weight: 0}]);
|
||||||
|
setValidity([...validity, {weightValid:false, usernameValid:false}])
|
||||||
};
|
};
|
||||||
|
|
||||||
const _onWeightInputChange = (value, index) => {
|
const _onWeightInputChange = (value, index) => {
|
||||||
@ -47,60 +53,71 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => {
|
|||||||
beneficiaries[0].weight = beneficiaries[0].weight - _diff;
|
beneficiaries[0].weight = beneficiaries[0].weight - _diff;
|
||||||
beneficiaries[index].weight = _value;
|
beneficiaries[index].weight = _value;
|
||||||
|
|
||||||
setBeneficiaries([...beneficiaries]);
|
validity[index].weightValid = _value > 0 && _value <= 10000;
|
||||||
|
|
||||||
|
setBeneficiaries(beneficiaries);
|
||||||
|
setValidity([...validity])
|
||||||
};
|
};
|
||||||
|
|
||||||
const _onUsernameInputChange = (value, index) => {
|
const _lookupAccounts = debounce((username, index)=>{
|
||||||
beneficiaries[index].account = value;
|
lookupAccounts(username).then((res) => {
|
||||||
|
|
||||||
setBeneficiaries([...beneficiaries]);
|
|
||||||
|
|
||||||
lookupAccounts(value).then((res) => {
|
|
||||||
const isValid =
|
const isValid =
|
||||||
res.includes(value) &&
|
res.includes(username)
|
||||||
beneficiaries[index].weight !== 0 &&
|
validity[index].usernameValid = isValid;
|
||||||
beneficiaries[index].weight <= 10000;
|
setValidity([...validity]);
|
||||||
beneficiaries[index].isValid = isValid;
|
|
||||||
setBeneficiaries([...beneficiaries]);
|
|
||||||
});
|
});
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
const _onUsernameInputChange = (value, index) => {
|
||||||
|
_lookupAccounts(value, index);
|
||||||
|
|
||||||
|
beneficiaries[index].account = value;
|
||||||
|
setBeneficiaries(beneficiaries);
|
||||||
};
|
};
|
||||||
|
|
||||||
const _isValid = () => {
|
const _isValid = () => {
|
||||||
return beneficiaries.every((item) => item.isValid);
|
return validity.every((item) => (item.usernameValid && item.weightValid));
|
||||||
};
|
};
|
||||||
|
|
||||||
const _onBlur = (item, index) => {
|
const _onBlur = (item) => {
|
||||||
if (item.weight === 0) {
|
if (item.weight === 0) {
|
||||||
const newBeneficiaries = [...beneficiaries];
|
const newBeneficiaries = [...beneficiaries];
|
||||||
remove(newBeneficiaries, (current) => {
|
const newValidity = [...validity];
|
||||||
return current.account === item.account;
|
|
||||||
});
|
const index = newBeneficiaries.findIndex((current)=>current.account === item.account);
|
||||||
|
if(index >= 0){
|
||||||
|
newBeneficiaries.splice(index, 1);
|
||||||
|
newValidity.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
setBeneficiaries(newBeneficiaries);
|
setBeneficiaries(newBeneficiaries);
|
||||||
|
setValidity(newValidity);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderInputs = ({ item, index }) => {
|
|
||||||
|
const renderInput = ({ item, index }) => {
|
||||||
const _isCurrentUser = item.account === username;
|
const _isCurrentUser = item.account === username;
|
||||||
|
const {weightValid, usernameValid} = validity[index];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.inputWrapper}>
|
<View style={styles.inputWrapper}>
|
||||||
<View style={styles.weightInput}>
|
<View style={styles.weightInput}>
|
||||||
<FormInput
|
<FormInput
|
||||||
isValid={_isCurrentUser || (item.weight !== 0 && item.weight <= 10000)}
|
isValid={_isCurrentUser || weightValid}
|
||||||
isEditable={!_isCurrentUser}
|
isEditable={!_isCurrentUser}
|
||||||
value={`${item.weight / 100}`}
|
value={`${item.weight / 100}`}
|
||||||
inputStyle={styles.weightFormInput}
|
inputStyle={styles.weightFormInput}
|
||||||
wrapperStyle={styles.weightFormInputWrapper}
|
wrapperStyle={styles.weightFormInputWrapper}
|
||||||
onChange={(value) => _onWeightInputChange(value, index)}
|
onChange={(value) => _onWeightInputChange(value, index)}
|
||||||
onBlur={() => _onBlur(item, index)}
|
onBlur={() => _onBlur(item)}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.usernameInput}>
|
<View style={styles.usernameInput}>
|
||||||
<FormInput
|
<FormInput
|
||||||
rightIconName="at"
|
rightIconName="at"
|
||||||
iconType="MaterialCommunityIcons"
|
iconType="MaterialCommunityIcons"
|
||||||
isValid={_isCurrentUser || item.isValid}
|
isValid={_isCurrentUser || usernameValid}
|
||||||
//isEditable={!_isCurrentUser}
|
//isEditable={!_isCurrentUser}
|
||||||
onChange={(value) => _onUsernameInputChange(value, index)}
|
onChange={(value) => _onUsernameInputChange(value, index)}
|
||||||
placeholder={intl.formatMessage({
|
placeholder={intl.formatMessage({
|
||||||
@ -117,12 +134,16 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const isAllValid = _isValid();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.bodyWrapper}>
|
<View style={styles.bodyWrapper}>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={beneficiaries}
|
data={beneficiaries}
|
||||||
renderItem={renderInputs}
|
renderItem={renderInput}
|
||||||
|
extraData={validity}
|
||||||
ListHeaderComponent={() => (
|
ListHeaderComponent={() => (
|
||||||
<View style={styles.inputWrapper}>
|
<View style={styles.inputWrapper}>
|
||||||
<View style={[styles.weightInput, { alignItems: 'center' }]}>
|
<View style={[styles.weightInput, { alignItems: 'center' }]}>
|
||||||
@ -142,15 +163,17 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, isDraft }) => {
|
|||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
ListFooterComponent={() => (
|
ListFooterComponent={() => (
|
||||||
<View style={{ alignItems: 'flex-end', marginTop: 20 }}>
|
<View style={{marginTop: 20 }}>
|
||||||
<Tag
|
<TextButton
|
||||||
value={intl.formatMessage({
|
text={intl.formatMessage({
|
||||||
id: 'beneficiary_modal.addAccount',
|
id: 'beneficiary_modal.addAccount',
|
||||||
})}
|
})}
|
||||||
isFilter
|
disabled={!isAllValid}
|
||||||
disabled={!_isValid()}
|
|
||||||
isPin={_isValid()}
|
|
||||||
onPress={_addAccount}
|
onPress={_addAccount}
|
||||||
|
textStyle={{
|
||||||
|
color:EStyleSheet.value(isAllValid?'$primaryBlue':"$iconColor"),
|
||||||
|
fontWeight:'bold'
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
@ -5,20 +5,21 @@ export default EStyleSheet.create({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
padding: 16,
|
padding: 16,
|
||||||
|
backgroundColor:'$modalBackground',
|
||||||
},
|
},
|
||||||
bodyWrapper: { flex: 3, paddingTop: 20 },
|
bodyWrapper: { flex: 3, paddingTop: 20 },
|
||||||
inputWrapper: { flexDirection: 'row', alignItems: 'center' },
|
inputWrapper: { flexDirection: 'row', alignItems: 'center' },
|
||||||
text: { color: '$primaryBlack', marginBottom: 8 },
|
text: { color: '$primaryBlack', marginBottom: 8 },
|
||||||
weightInput: { flex: 1 },
|
weightInput: { flex: 1 },
|
||||||
weightFormInput: { textAlign: 'center', color: '$primaryBlack' },
|
weightFormInput: { textAlign: 'center', color: '$primaryBlack' },
|
||||||
weightFormInputWrapper: { marginTop: 0 },
|
weightFormInputWrapper: { marginTop: 8, borderRadius:12 },
|
||||||
usernameInput: { flex: 3, color: '$primaryBlack', marginLeft: 16 },
|
usernameInput: { flex: 3, color: '$primaryBlack', marginLeft: 16 },
|
||||||
usernameFormInputWrapper: { marginTop: 0, marginLeft: 10 },
|
usernameFormInputWrapper: { marginTop: 8, marginLeft: 10, borderRadius:12 },
|
||||||
footerWrapper: { flex: 1 },
|
footerWrapper: { paddingTop:16, paddingBottom:16 },
|
||||||
saveButton: {
|
saveButton: {
|
||||||
width: 100,
|
width: 140,
|
||||||
height: 44,
|
height: 44,
|
||||||
alignSelf: 'center',
|
alignSelf: 'flex-end',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
});
|
});
|
@ -3,9 +3,9 @@ import { Text, View, TouchableWithoutFeedback } from 'react-native';
|
|||||||
|
|
||||||
import styles from './textButtonStyles';
|
import styles from './textButtonStyles';
|
||||||
|
|
||||||
const TextButtonView = ({ text, onPress, style, textStyle }) => (
|
const TextButtonView = ({ text, onPress, style, textStyle, disabled }) => (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<TouchableWithoutFeedback style={[styles.button]} onPress={() => onPress && onPress()}>
|
<TouchableWithoutFeedback style={[styles.button]} disabled={disabled} onPress={() => onPress && onPress()}>
|
||||||
<View style={style}>
|
<View style={style}>
|
||||||
<Text style={[styles.buttonText, textStyle]}>{text}</Text>
|
<Text style={[styles.buttonText, textStyle]}>{text}</Text>
|
||||||
</View>
|
</View>
|
Loading…
Reference in New Issue
Block a user