initial lint --no-verify

This commit is contained in:
noumantahir 2023-11-02 12:07:22 +05:00 committed by Nouman Tahir
parent c3bcb44762
commit c4fca1e793
123 changed files with 2499 additions and 2789 deletions

View File

@ -12,5 +12,6 @@
}, },
"workbench.colorCustomizations": { "workbench.colorCustomizations": {
"editorUnnecessaryCode.border": "#dd7aab" "editorUnnecessaryCode.border": "#dd7aab"
} },
"java.compile.nullAnalysis.mode": "automatic"
} }

View File

@ -2,80 +2,77 @@ import { TextStyle, StyleSheet, ViewStyle, ImageStyle } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({ export default EStyleSheet.create({
modalStyle: { modalStyle: {
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
margin:0, margin: 0,
paddingTop:32, paddingTop: 32,
paddingBottom:8, paddingBottom: 8,
}, },
sheetContent: { sheetContent: {
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
position:'absolute', position: 'absolute',
bottom:0, bottom: 0,
left:0, left: 0,
right:0, right: 0,
zIndex:999 zIndex: 999,
}, },
container:{ container: {
marginTop:16, marginTop: 16,
marginBottom:36, marginBottom: 36,
paddingHorizontal:24, paddingHorizontal: 24,
alignItems:'center', alignItems: 'center',
justifyContent:'space-between', justifyContent: 'space-between',
} as ViewStyle, } as ViewStyle,
imageStyle:{ imageStyle: {
marginTop:8, marginTop: 8,
height:150, height: 150,
width:'100%', width: '100%',
} as ImageStyle, } as ImageStyle,
textContainer:{ textContainer: {
marginTop:32, marginTop: 32,
marginBottom:44, marginBottom: 44,
} as ViewStyle, } as ViewStyle,
title: { title: {
color: '$primaryBlack', color: '$primaryBlack',
alignSelf: 'center', alignSelf: 'center',
textAlign: 'center', textAlign: 'center',
fontSize: 20, fontSize: 20,
fontWeight: '800', fontWeight: '800',
} as TextStyle, } as TextStyle,
bodyText: { bodyText: {
color: '$primaryBlack', color: '$primaryBlack',
alignSelf: 'center', alignSelf: 'center',
textAlign: 'center', textAlign: 'center',
fontSize: 16, fontSize: 16,
fontWeight: '600', fontWeight: '600',
marginTop:4, marginTop: 4,
} as TextStyle, } as TextStyle,
btnText:{ btnText: {
color:'$pureWhite' color: '$pureWhite',
} as TextStyle, } as TextStyle,
button:{ button: {
backgroundColor: '$primaryBlue',
minWidth: 150,
paddingVertical: 16,
marginVertical: 8,
borderRadius: 32,
justifyContent: 'center',
alignItems: 'center',
} as ViewStyle,
backgroundColor:'$primaryBlue', actionPanel: {
minWidth:150, width: '100%',
paddingVertical:16, flexDirection: 'row',
marginVertical:8, flexWrap: 'wrap',
borderRadius:32, justifyContent: 'space-around',
justifyContent:'center', alignItems: 'center',
alignItems:'center' } as ViewStyle,
} as ViewStyle, });
actionPanel:{
width:'100%',
flexDirection:'row',
flexWrap:'wrap',
justifyContent:'space-around',
alignItems:'center',
} as ViewStyle,
})

View File

@ -1,22 +1,22 @@
import { ViewStyle } from "react-native" import { ViewStyle } from 'react-native';
import EStyleSheet from "react-native-extended-stylesheet" import EStyleSheet from 'react-native-extended-stylesheet';
import { ImageStyle } from "react-native-fast-image" import { ImageStyle } from 'react-native-fast-image';
export default EStyleSheet.create({ export default EStyleSheet.create({
hiveEngineWrapper: { hiveEngineWrapper: {
position: 'absolute', position: 'absolute',
top: -6, top: -6,
right: 4, right: 4,
borderRadius: 10, borderRadius: 10,
padding: 1, padding: 1,
backgroundColor: '$pureWhite', backgroundColor: '$pureWhite',
} as ViewStyle, } as ViewStyle,
hiveEngineLogo: { hiveEngineLogo: {
height: 14, height: 14,
width: 14 width: 14,
} as ImageStyle, } as ImageStyle,
logo: { logo: {
height: 30, height: 30,
width: 30, width: 30,
} as ImageStyle, } as ImageStyle,
}) });

View File

@ -12,45 +12,45 @@ interface WritePostButtonProps {
onPress: () => void; onPress: () => void;
} }
export const WritePostButton = forwardRef(({ placeholderId: placeholder, onPress }: WritePostButtonProps, ref) => { export const WritePostButton = forwardRef(
const intl = useIntl(); ({ placeholderId: placeholder, onPress }: WritePostButtonProps, ref) => {
const intl = useIntl();
const animatedContainer = useRef<AnimatedView>(); const animatedContainer = useRef<AnimatedView>();
const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn); const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn);
const currentAccount = useAppSelector((state) => state.account.currentAccount); const currentAccount = useAppSelector((state) => state.account.currentAccount);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
bounce: () => { bounce: () => {
console.log('bouncing'); console.log('bouncing');
if (animatedContainer.current) { if (animatedContainer.current) {
animatedContainer.current.swing(1000); animatedContainer.current.swing(1000);
}
},
}));
const _onPress = () => {
if (!isLoggedIn) {
showLoginAlert({ intl });
return;
} }
}, if (onPress) {
})); onPress();
}
};
const _onPress = () => { return (
if (!isLoggedIn) { <AnimatedView ref={animatedContainer}>
showLoginAlert({ intl }); <TouchableOpacity onPress={_onPress}>
return; <View style={styles.container}>
} <UserAvatar username={currentAccount.username} />
if (onPress) { <View style={styles.inputContainer}>
onPress(); <Text style={styles.inputPlaceholder}>{intl.formatMessage({ id: placeholder })}</Text>
} </View>
};
return (
<AnimatedView ref={animatedContainer}>
<TouchableOpacity onPress={_onPress}>
<View style={styles.container}>
<UserAvatar username={currentAccount.username} />
<View style={styles.inputContainer}>
<Text style={styles.inputPlaceholder}>
{intl.formatMessage({ id: placeholder })}
</Text>
</View> </View>
</View> </TouchableOpacity>
</TouchableOpacity> </AnimatedView>
</AnimatedView> );
); },
}); );

View File

@ -1 +1 @@
export * from './container/writePostButton'; export * from './container/writePostButton';

View File

@ -196,8 +196,8 @@ const BasicHeaderView = ({
size={28} size={28}
onPress={() => handleBrowserIconPress()} onPress={() => handleBrowserIconPress()}
iconStyle={styles.rightIcon} iconStyle={styles.rightIcon}
name={'open-in-browser'} name="open-in-browser"
iconType={'MaterialIcons'} iconType="MaterialIcons"
/> />
)} )}
</View> </View>

View File

@ -16,28 +16,22 @@ const BoostPlaceHolder = () => {
const isDarkTheme = useSelector((state) => state.application.isDarkTeme); const isDarkTheme = useSelector((state) => state.application.isDarkTeme);
const color = isDarkTheme ? '#2e3d51' : '#f5f5f5'; const color = isDarkTheme ? '#2e3d51' : '#f5f5f5';
times(parseInt(ratio), (i) => { times(parseInt(ratio), (i) => {
listElements.push(<View style={styles.container} key={`key-${i.toString()}`}> listElements.push(
<View style={styles.line}> <View style={styles.container} key={`key-${i.toString()}`}>
<Placeholder.Box color={color} width={90} height={40} animate="fade" /> <View style={styles.line}>
<View style={styles.paragraphWrapper}> <Placeholder.Box color={color} width={90} height={40} animate="fade" />
<View style={styles.paragraphWrapper}>
<Placeholder.Box color={color} width={140} radius={25} height={50} animate="fade" />
</View>
<Placeholder.Box <Placeholder.Box
style={styles.rightBox}
color={color} color={color}
width={140} width={20}
radius={25} height={10}
height={50}
animate="fade" animate="fade"
/> />
</View> </View>
<Placeholder.Box </View>,
style={styles.rightBox}
color={color}
width={20}
height={10}
animate="fade"
/>
</View>
</View>
); );
}); });

View File

@ -11,7 +11,6 @@ const CommentPlaceHolderView = () => {
height: 72, height: 72,
}; };
const isDarkTheme = useSelector((state) => state.application.isDarkTheme); const isDarkTheme = useSelector((state) => state.application.isDarkTheme);
const color = isDarkTheme ? '#2e3d51' : '#f5f5f5'; const color = isDarkTheme ? '#2e3d51' : '#f5f5f5';
@ -33,9 +32,6 @@ const CommentPlaceHolderView = () => {
/> />
</View> </View>
); );
}; };
export default CommentPlaceHolderView; export default CommentPlaceHolderView;

View File

@ -7,7 +7,7 @@ import { useSelector } from 'react-redux';
import styles from './postCardPlaceHolderStyles'; import styles from './postCardPlaceHolderStyles';
// TODO: make container for place holder wrapper after alpha // TODO: make container for place holder wrapper after alpha
const PostCardPlaceHolder = () => { const PostCardPlaceHolder = () => {
const isDarkTheme = useSelector((state) => state.application.isDarkTheme) const isDarkTheme = useSelector((state) => state.application.isDarkTheme);
const color = isDarkTheme ? '#2e3d51' : '#f5f5f5'; const color = isDarkTheme ? '#2e3d51' : '#f5f5f5';
return ( return (
<View style={styles.container}> <View style={styles.container}>
@ -25,6 +25,5 @@ const PostCardPlaceHolder = () => {
</View> </View>
</View> </View>
); );
}; };
export default PostCardPlaceHolder; export default PostCardPlaceHolder;

View File

@ -7,7 +7,6 @@ import { useSelector } from 'react-redux';
import styles from './listItemPlaceHolderStyles'; import styles from './listItemPlaceHolderStyles';
const ListItemPlaceHolderView = () => { const ListItemPlaceHolderView = () => {
const isDarkTheme = useSelector((state) => state.application.isDarkTheme); const isDarkTheme = useSelector((state) => state.application.isDarkTheme);
const color = isDarkTheme ? '#2e3d51' : '#f5f5f5'; const color = isDarkTheme ? '#2e3d51' : '#f5f5f5';
return ( return (
@ -27,7 +26,6 @@ const ListItemPlaceHolderView = () => {
</View> </View>
</View> </View>
); );
}; };
export default ListItemPlaceHolderView; export default ListItemPlaceHolderView;

View File

@ -4,6 +4,7 @@ import LottieView from 'lottie-react-native';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import styles from './postCardPlaceHolderStyles'; import styles from './postCardPlaceHolderStyles';
import getWindowDimensions from '../../../../utils/getWindowDimensions'; import getWindowDimensions from '../../../../utils/getWindowDimensions';
const PostCardPlaceHolder = () => { const PostCardPlaceHolder = () => {
const animationStyle = { const animationStyle = {
width: getWindowDimensions().nativeWidth - 32, width: getWindowDimensions().nativeWidth - 32,
@ -29,6 +30,5 @@ const PostCardPlaceHolder = () => {
/> />
</View> </View>
); );
}; };
export default PostCardPlaceHolder; export default PostCardPlaceHolder;

View File

@ -4,8 +4,8 @@ import LottieView from 'lottie-react-native';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import getWindowDimensions from '../../../../utils/getWindowDimensions'; import getWindowDimensions from '../../../../utils/getWindowDimensions';
const PostPlaceHolder = () => {
const PostPlaceHolder = () => {
const isDarkTheme = useSelector((state) => state.application.isDarkTheme); const isDarkTheme = useSelector((state) => state.application.isDarkTheme);
const color = isDarkTheme ? '#2e3d51' : '#f5f5f5'; const color = isDarkTheme ? '#2e3d51' : '#f5f5f5';
@ -27,7 +27,6 @@ const PostPlaceHolder = () => {
/> />
</View> </View>
); );
}; };
export default PostPlaceHolder; export default PostPlaceHolder;

View File

@ -29,7 +29,6 @@ const ProfileSummaryPlaceHolder = () => {
</View> </View>
</View> </View>
); );
}; };
export default ProfileSummaryPlaceHolder; export default ProfileSummaryPlaceHolder;

View File

@ -29,7 +29,6 @@ const WalletDetailsPlaceHolder = () => {
const isDarkTheme = useSelector((state) => state.application.isDarkTheme); const isDarkTheme = useSelector((state) => state.application.isDarkTheme);
const color = isDarkTheme ? '#2e3d51' : '#f5f5f5'; const color = isDarkTheme ? '#2e3d51' : '#f5f5f5';
return ( return (
<View style={styles.container}> <View style={styles.container}>
<View style={styles.textWrapper}> <View style={styles.textWrapper}>
@ -37,12 +36,8 @@ const WalletDetailsPlaceHolder = () => {
</View> </View>
{listPlaceHolderView(color)} {listPlaceHolderView(color)}
</View> </View>
) );
};
}
export default WalletDetailsPlaceHolder; export default WalletDetailsPlaceHolder;
/* eslint-enable */ /* eslint-enable */

View File

@ -101,6 +101,4 @@ export default EStyleSheet.create({
tooltipText: { tooltipText: {
color: '$primaryDarkText', color: '$primaryDarkText',
}, },
}); });

View File

@ -80,8 +80,8 @@ export default EStyleSheet.create({
justifyContent: 'center', justifyContent: 'center',
alignSelf: 'center', alignSelf: 'center',
}, },
cancelIcon:{ cancelIcon: {
marginLeft:8, marginLeft: 8,
}, },
dropdownWrapper: { dropdownWrapper: {
flex: 1, flex: 1,

View File

@ -3,31 +3,31 @@ import { View, FlatList, Text } from 'react-native';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { isArray, debounce } from 'lodash'; import { isArray, debounce } from 'lodash';
import EStyleSheet from 'react-native-extended-stylesheet';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { lookupAccounts } from '../../providers/hive/dhive'; import { lookupAccounts } from '../../providers/hive/dhive';
import { FormInput, MainButton, TextButton } from '..'; import { FormInput, MainButton, TextButton } from '..';
import styles from './beneficiaryModalStyles'; import styles from './beneficiaryModalStyles';
import EStyleSheet from 'react-native-extended-stylesheet';
import IconButton from '../iconButton'; import IconButton from '../iconButton';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import { useAppSelector } from '../../hooks'; import { useAppSelector } from '../../hooks';
import { Beneficiary } from '../../redux/reducers/editorReducer'; import { Beneficiary } from '../../redux/reducers/editorReducer';
import { TEMP_BENEFICIARIES_ID } from '../../redux/constants/constants'; import { TEMP_BENEFICIARIES_ID } from '../../redux/constants/constants';
interface BeneficiaryModal { interface BeneficiaryModal {
username:string, username: string;
draftId:string, draftId: string;
handleOnSaveBeneficiaries:()=>void handleOnSaveBeneficiaries: () => void;
} }
const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => { const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
const intl = useIntl(); const intl = useIntl();
const beneficiariesMap = useAppSelector(state => state.editor.beneficiariesMap) const beneficiariesMap = useAppSelector((state) => state.editor.beneficiariesMap);
const [beneficiaries, setBeneficiaries] = useState<Beneficiary[]>([ const [beneficiaries, setBeneficiaries] = useState<Beneficiary[]>([
{ account: username, weight: 10000, isValid: true}, { account: username, weight: 10000, isValid: true },
]); ]);
const [newUsername, setNewUsername] = useState(''); const [newUsername, setNewUsername] = useState('');
@ -37,14 +37,13 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
const [newEditable, setNewEditable] = useState(false); const [newEditable, setNewEditable] = useState(false);
useEffect(() => { useEffect(() => {
readTempBeneficiaries(); readTempBeneficiaries();
}, [draftId]); }, [draftId]);
const readTempBeneficiaries = async () => { const readTempBeneficiaries = async () => {
if(beneficiariesMap){ if (beneficiariesMap) {
const tempBeneficiaries = beneficiariesMap[draftId || TEMP_BENEFICIARIES_ID]; const tempBeneficiaries = beneficiariesMap[draftId || TEMP_BENEFICIARIES_ID];
if (isArray(tempBeneficiaries)) { if (isArray(tempBeneficiaries)) {
tempBeneficiaries.forEach((item) => { tempBeneficiaries.forEach((item) => {
item.isValid = true; item.isValid = true;
@ -52,28 +51,24 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
setBeneficiaries(tempBeneficiaries); setBeneficiaries(tempBeneficiaries);
} }
} }
}; };
const _onSavePress = () => { const _onSavePress = () => {
if(newEditable){ if (newEditable) {
beneficiaries.push({ beneficiaries.push({
account:newUsername, account: newUsername,
weight:newWeight weight: newWeight,
}) });
} }
handleOnSaveBeneficiaries(beneficiaries); handleOnSaveBeneficiaries(beneficiaries);
} };
const _addAccount = () => { const _addAccount = () => {
if (isUsernameValid && isWeightValid) {
if(isUsernameValid && isWeightValid){
beneficiaries.push({ beneficiaries.push({
account:newUsername, account: newUsername,
weight:newWeight, weight: newWeight,
}) });
setBeneficiaries([...beneficiaries]); setBeneficiaries([...beneficiaries]);
} }
@ -84,43 +79,33 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
setNewEditable(true); setNewEditable(true);
}; };
const _onWeightInputChange = (value) => { const _onWeightInputChange = (value) => {
let _value = (parseInt(value, 10) || 0) * 100; const _value = (parseInt(value, 10) || 0) * 100;
const _diff = _value - newWeight; const _diff = _value - newWeight;
beneficiaries[0].weight = beneficiaries[0].weight - _diff; beneficiaries[0].weight = beneficiaries[0].weight - _diff;
setNewWeight(_value) setNewWeight(_value);
setIsWeightValid(_value > 0 && _value <= 10000) setIsWeightValid(_value > 0 && _value <= 10000);
setBeneficiaries([...beneficiaries]); setBeneficiaries([...beneficiaries]);
}; };
const _lookupAccounts = debounce((username) => { const _lookupAccounts = debounce((username) => {
lookupAccounts(username).then((res) => { lookupAccounts(username).then((res) => {
const isValid = res.includes(username) const isValid = res.includes(username);
//check if username duplicates else lookup contacts, done here to avoid debounce and post call mismatch // check if username duplicates else lookup contacts, done here to avoid debounce and post call mismatch
const notExistAlready = !beneficiaries.find((item)=>item.account === username); const notExistAlready = !beneficiaries.find((item) => item.account === username);
setIsUsernameValid(isValid && notExistAlready) setIsUsernameValid(isValid && notExistAlready);
}); });
}, 1000) }, 1000);
const _onUsernameInputChange = (value) => { const _onUsernameInputChange = (value) => {
setNewUsername(value); setNewUsername(value);
_lookupAccounts(value); _lookupAccounts(value);
}; };
const _isValid = () => { const _isValid = () => {
return !newEditable || (isUsernameValid && isWeightValid); return !newEditable || (isUsernameValid && isWeightValid);
}; };
const _renderHeader = () => ( const _renderHeader = () => (
<View style={styles.inputWrapper}> <View style={styles.inputWrapper}>
<View style={[styles.weightInput, { alignItems: 'center' }]}> <View style={[styles.weightInput, { alignItems: 'center' }]}>
@ -138,23 +123,20 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
</Text> </Text>
</View> </View>
</View> </View>
) );
const _renderInput = () => { const _renderInput = () => {
const _onCancelPress = () => { const _onCancelPress = () => {
if(newWeight){ if (newWeight) {
beneficiaries[0].weight = beneficiaries[0].weight + newWeight; beneficiaries[0].weight = beneficiaries[0].weight + newWeight;
setBeneficiaries([...beneficiaries]) setBeneficiaries([...beneficiaries]);
setNewWeight(0); setNewWeight(0);
} }
setNewEditable(false); setNewEditable(false);
setIsWeightValid(false); setIsWeightValid(false);
setIsUsernameValid(false); setIsUsernameValid(false);
setNewUsername(''); setNewUsername('');
};
}
return ( return (
<View style={styles.inputWrapper}> <View style={styles.inputWrapper}>
@ -165,8 +147,8 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
inputStyle={styles.weightFormInput} inputStyle={styles.weightFormInput}
wrapperStyle={styles.weightFormInputWrapper} wrapperStyle={styles.weightFormInputWrapper}
onChange={(value) => _onWeightInputChange(value)} onChange={(value) => _onWeightInputChange(value)}
onBlur={() => {}}//_onBlur(item)} onBlur={() => {}} // _onBlur(item)}
keyboardType='numeric' keyboardType="numeric"
/> />
</View> </View>
@ -187,40 +169,36 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
/> />
</View> </View>
<IconButton <IconButton
name="close" name="close"
iconType="MaterialCommunityIcons" iconType="MaterialCommunityIcons"
color={EStyleSheet.value('$primaryBlack')} color={EStyleSheet.value('$primaryBlack')}
size={24} size={24}
iconStyle={{paddingLeft:8}} iconStyle={{ paddingLeft: 8 }}
onPress={_onCancelPress} onPress={_onCancelPress}
/> />
</View> </View>
); );
}; };
const _renderFooter = () => ( const _renderFooter = () => (
<> <>
{newEditable && _renderInput()} {newEditable && _renderInput()}
<View style={{marginTop: 20, marginBottom:32 }}> <View style={{ marginTop: 20, marginBottom: 32 }}>
<TextButton <TextButton
text={intl.formatMessage({ text={intl.formatMessage({
id: 'beneficiary_modal.addAccount', id: 'beneficiary_modal.addAccount',
})} })}
disabled={!isAllValid} disabled={!isAllValid}
onPress={_addAccount} onPress={_addAccount}
textStyle={{ textStyle={{
color:EStyleSheet.value(isAllValid?'$primaryBlue':"$iconColor"), color: EStyleSheet.value(isAllValid ? '$primaryBlue' : '$iconColor'),
fontWeight:'bold' fontWeight: 'bold',
}} }}
/> />
</View> </View>
</> </>
);
)
const _renderItem = ({ item, index }) => { const _renderItem = ({ item, index }) => {
const _isCurrentUser = item.account === username; const _isCurrentUser = item.account === username;
@ -229,8 +207,7 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
beneficiaries[0].weight = beneficiaries[0].weight + item.weight; beneficiaries[0].weight = beneficiaries[0].weight + item.weight;
beneficiaries.splice(index, 1); beneficiaries.splice(index, 1);
setBeneficiaries([...beneficiaries]); setBeneficiaries([...beneficiaries]);
} };
return ( return (
<View style={styles.inputWrapper}> <View style={styles.inputWrapper}>
@ -241,7 +218,7 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
value={`${item.weight / 100}`} value={`${item.weight / 100}`}
inputStyle={styles.weightFormInput} inputStyle={styles.weightFormInput}
wrapperStyle={styles.weightFormInputWrapper} wrapperStyle={styles.weightFormInputWrapper}
/> />
</View> </View>
<View style={styles.usernameInput}> <View style={styles.usernameInput}>
@ -256,28 +233,25 @@ const BeneficiaryModal = ({ username, handleOnSaveBeneficiaries, draftId }) => {
/> />
</View> </View>
{!_isCurrentUser ? ( {!_isCurrentUser ? (
<IconButton <IconButton
name="close" name="close"
iconType="MaterialCommunityIcons" iconType="MaterialCommunityIcons"
size={24} size={24}
color={EStyleSheet.value('$primaryBlack')} color={EStyleSheet.value('$primaryBlack')}
iconStyle={{paddingLeft:8}} iconStyle={{ paddingLeft: 8 }}
onPress={_onRemovePress} onPress={_onRemovePress}
/> />
):( ) : (
<View style={{width:30}} /> <View style={{ width: 30 }} />
)} )}
</View> </View>
); );
}; };
const isAllValid = _isValid(); const isAllValid = _isValid();
return ( return (
<View style={styles.container}> <View style={styles.container}>
<KeyboardAwareScrollView style={styles.bodyWrapper}> <KeyboardAwareScrollView style={styles.bodyWrapper}>
<FlatList <FlatList
data={beneficiaries} data={beneficiaries}

View File

@ -78,7 +78,7 @@ const BeneficiarySelectionContent = ({
]; ];
if (isArray(tempBeneficiaries) && tempBeneficiaries.length > 0) { if (isArray(tempBeneficiaries) && tempBeneficiaries.length > 0) {
//weight correction algorithm. // weight correction algorithm.
let othersWeight = 0; let othersWeight = 0;
tempBeneficiaries.forEach((item, index) => { tempBeneficiaries.forEach((item, index) => {
if (index > 0) { if (index > 0) {
@ -100,7 +100,7 @@ const BeneficiarySelectionContent = ({
: [DEFAULT_BENEFICIARY]; : [DEFAULT_BENEFICIARY];
if (isArray(tempBeneficiaries) && tempBeneficiaries.length > 0) { if (isArray(tempBeneficiaries) && tempBeneficiaries.length > 0) {
//weight correction algorithm. // weight correction algorithm.
let othersWeight = 0; let othersWeight = 0;
tempBeneficiaries.forEach((item, index) => { tempBeneficiaries.forEach((item, index) => {
if (index > 0) { if (index > 0) {
@ -114,7 +114,7 @@ const BeneficiarySelectionContent = ({
}; };
const _saveBeneficiaries = (value: Beneficiary[]) => { const _saveBeneficiaries = (value: Beneficiary[]) => {
const filteredBeneficiaries = value.filter((item) => item.account !== username); //remove default beneficiary from array while saving const filteredBeneficiaries = value.filter((item) => item.account !== username); // remove default beneficiary from array while saving
if (handleSaveBeneficiary) { if (handleSaveBeneficiary) {
handleSaveBeneficiary(filteredBeneficiaries); handleSaveBeneficiary(filteredBeneficiaries);
} else { } else {
@ -151,7 +151,7 @@ const BeneficiarySelectionContent = ({
}; };
const _onWeightInputChange = (value: string) => { const _onWeightInputChange = (value: string) => {
let _value = (parseInt(value, 10) || 0) * 100; const _value = (parseInt(value, 10) || 0) * 100;
const _diff = _value - newWeight; const _diff = _value - newWeight;
const newAuthorWeight = beneficiaries[0].weight - _diff; const newAuthorWeight = beneficiaries[0].weight - _diff;
@ -165,7 +165,7 @@ const BeneficiarySelectionContent = ({
const _lookupAccounts = debounce((username) => { const _lookupAccounts = debounce((username) => {
lookupAccounts(username).then((res) => { lookupAccounts(username).then((res) => {
const isValid = res.includes(username); const isValid = res.includes(username);
//check if username duplicates else lookup contacts, done here to avoid debounce and post call mismatch // check if username duplicates else lookup contacts, done here to avoid debounce and post call mismatch
const notExistAlready = !beneficiaries.find((item) => item.account === username); const notExistAlready = !beneficiaries.find((item) => item.account === username);
setIsUsernameValid(isValid && notExistAlready); setIsUsernameValid(isValid && notExistAlready);
}); });

View File

@ -7,6 +7,7 @@ import { SafeAreaView, View, TouchableOpacity, Alert } from 'react-native';
// Constants // Constants
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { BottomTabBarProps } from '@react-navigation/bottom-tabs'; import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
import { useIntl } from 'react-intl';
import ROUTES from '../../../constants/routeNames'; import ROUTES from '../../../constants/routeNames';
// Styles // Styles
@ -16,7 +17,6 @@ import scalePx from '../../../utils/scalePx';
import { showReplyModal, updateActiveBottomTab } from '../../../redux/actions/uiAction'; import { showReplyModal, updateActiveBottomTab } from '../../../redux/actions/uiAction';
import { useAppSelector } from '../../../hooks'; import { useAppSelector } from '../../../hooks';
import showLoginAlert from '../../../utils/showLoginAlert'; import showLoginAlert from '../../../utils/showLoginAlert';
import { useIntl } from 'react-intl';
const BottomTabBarView = ({ const BottomTabBarView = ({
state: { routes, index }, state: { routes, index },
@ -31,19 +31,15 @@ const BottomTabBarView = ({
dispatch(updateActiveBottomTab(routes[index].name)); dispatch(updateActiveBottomTab(routes[index].name));
}, [index]); }, [index]);
const _jumpTo = (route, isFocused) => { const _jumpTo = (route, isFocused) => {
if (route.name === ROUTES.TABBAR.POST_BUTTON) { if (route.name === ROUTES.TABBAR.POST_BUTTON) {
if (!isLoggedIn) {
if(!isLoggedIn){ showLoginAlert({ intl });
showLoginAlert({intl})
return; return;
} }
if (routes[index].name === ROUTES.TABBAR.WAVES) { if (routes[index].name === ROUTES.TABBAR.WAVES) {
dispatch(showReplyModal({mode:'wave'})); dispatch(showReplyModal({ mode: 'wave' }));
} else { } else {
navigation.navigate(ROUTES.SCREENS.EDITOR, { key: 'editor_post' }); navigation.navigate(ROUTES.SCREENS.EDITOR, { key: 'editor_post' });
} }
@ -63,8 +59,6 @@ const BottomTabBarView = ({
} }
}; };
const _tabButtons = routes.map((route, idx) => { const _tabButtons = routes.map((route, idx) => {
const { tabBarActiveTintColor, tabBarInactiveTintColor } = descriptors[route.key].options; const { tabBarActiveTintColor, tabBarInactiveTintColor } = descriptors[route.key].options;
const isFocused = index == idx; const isFocused = index == idx;
@ -88,7 +82,6 @@ const BottomTabBarView = ({
_iconProps.iconType = 'MaterialCommunityIcons'; _iconProps.iconType = 'MaterialCommunityIcons';
_tabBarIcon = <Icon {..._iconProps} />; _tabBarIcon = <Icon {..._iconProps} />;
break; break;
} }
return ( return (
@ -98,8 +91,6 @@ const BottomTabBarView = ({
); );
}); });
return <SafeAreaView style={styles.wrapper}>{_tabButtons}</SafeAreaView>; return <SafeAreaView style={styles.wrapper}>{_tabButtons}</SafeAreaView>;
}; };

View File

@ -73,7 +73,7 @@ const CommentView = ({
const _handleOnContentPress = () => { const _handleOnContentPress = () => {
openReplyThread(comment); openReplyThread(comment);
} };
const _handleOnReplyPress = () => { const _handleOnReplyPress = () => {
if (isLoggedIn) { if (isLoggedIn) {
@ -97,7 +97,6 @@ const CommentView = ({
); );
const _renderComment = () => { const _renderComment = () => {
const _hideContent = isMuted || comment.author_reputation < 25 || comment.net_rshares < 0; const _hideContent = isMuted || comment.author_reputation < 25 || comment.net_rshares < 0;
return ( return (
@ -219,9 +218,9 @@ const CommentView = ({
const customContainerStyle = const customContainerStyle =
_depth > 1 _depth > 1
? { ? {
paddingLeft: (_depth - 2) * 44, paddingLeft: (_depth - 2) * 44,
backgroundColor: EStyleSheet.value('$primaryLightBackground'), backgroundColor: EStyleSheet.value('$primaryLightBackground'),
} }
: null; : null;
return ( return (

View File

@ -52,7 +52,7 @@ const CommentsContainer = ({
incrementRepliesCount, incrementRepliesCount,
handleOnReplyPress, handleOnReplyPress,
handleOnCommentsLoaded, handleOnCommentsLoaded,
postType postType,
}) => { }) => {
const navigation = useNavigation(); const navigation = useNavigation();
const postsCachePrimer = postQueries.usePostsCachePrimer(); const postsCachePrimer = postQueries.usePostsCachePrimer();
@ -172,7 +172,7 @@ const CommentsContainer = ({
handleOnCommentsLoaded(); handleOnCommentsLoaded();
} }
}) })
.catch(() => { }); .catch(() => {});
} }
}; };
@ -244,13 +244,11 @@ const CommentsContainer = ({
}); });
}; };
const _handleOnUserPress = (username) => { const _handleOnUserPress = (username) => {
if (username) { if (username) {
dispatch(showProfileModal(username)) dispatch(showProfileModal(username));
} }
};
}
const _openReplyThread = (comment) => { const _openReplyThread = (comment) => {
postsCachePrimer.cachePost(comment); postsCachePrimer.cachePost(comment);

View File

@ -42,7 +42,7 @@ const CommentsView = ({
incrementRepliesCount, incrementRepliesCount,
postContentView, postContentView,
isLoading, isLoading,
postType postType,
}) => { }) => {
const [selectedComment, setSelectedComment] = useState(null); const [selectedComment, setSelectedComment] = useState(null);
const intl = useIntl(); const intl = useIntl();
@ -51,7 +51,6 @@ const CommentsView = ({
const postInteractionRef = useRef(null); const postInteractionRef = useRef(null);
const _openCommentMenu = (item) => { const _openCommentMenu = (item) => {
if (handleOnOptionsPress) { if (handleOnOptionsPress) {
handleOnOptionsPress(item); handleOnOptionsPress(item);
} else if (commentMenu.current) { } else if (commentMenu.current) {
@ -79,8 +78,8 @@ const CommentsView = ({
const _onUpvotePress = ({ content, anchorRect, showPayoutDetails, onVotingStart }) => { const _onUpvotePress = ({ content, anchorRect, showPayoutDetails, onVotingStart }) => {
if (upvotePopoverRef.current) { if (upvotePopoverRef.current) {
const postType =
const postType = content.parent_author === 'ecency.waves' ? PostTypes.WAVE : PostTypes.COMMENT; content.parent_author === 'ecency.waves' ? PostTypes.WAVE : PostTypes.COMMENT;
upvotePopoverRef.current.showPopover({ upvotePopoverRef.current.showPopover({
anchorRect, anchorRect,
@ -147,9 +146,9 @@ const CommentsView = ({
const styleOerride = const styleOerride =
commentNumber > 1 commentNumber > 1
? { ? {
backgroundColor: EStyleSheet.value('$primaryLightBackground'), backgroundColor: EStyleSheet.value('$primaryLightBackground'),
marginTop: 8, marginTop: 8,
} }
: null; : null;
const _renderEmptyContent = () => { const _renderEmptyContent = () => {
@ -169,7 +168,7 @@ const CommentsView = ({
return ( return (
<Fragment> <Fragment>
<FlashList <FlashList
contentContainerStyle={{ padding: 0, ...styles.list, ...styleOerride, }} contentContainerStyle={{ padding: 0, ...styles.list, ...styleOerride }}
data={comments} data={comments}
keyExtractor={(item) => item.author + item.permlink} keyExtractor={(item) => item.author + item.permlink}
renderItem={_renderItem} renderItem={_renderItem}

View File

@ -5,6 +5,7 @@ import { injectIntl } from 'react-intl';
// Utils // Utils
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
import ESStyleSheet from 'react-native-extended-stylesheet';
import { getTimeFromNow } from '../../../utils/time'; import { getTimeFromNow } from '../../../utils/time';
// Components // Components
@ -16,7 +17,6 @@ import { OptionsModal } from '../../atoms';
import styles from './draftListItemStyles'; import styles from './draftListItemStyles';
import { ScheduledPostStatus } from '../../../providers/ecency/ecency.types'; import { ScheduledPostStatus } from '../../../providers/ecency/ecency.types';
import { PopoverWrapper } from '../../popoverWrapper/popoverWrapperView'; import { PopoverWrapper } from '../../popoverWrapper/popoverWrapperView';
import ESStyleSheet from 'react-native-extended-stylesheet';
const DraftListItemView = ({ const DraftListItemView = ({
title, title,

View File

@ -1,7 +1,6 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { View } from 'react-native'; import { View } from 'react-native';
import { useSelector } from 'react-redux'; import { useSelector, connect } from 'react-redux';
import { connect } from 'react-redux';
// Constants // Constants
// Components // Components
@ -53,7 +52,6 @@ class TitleAreaView extends Component {
const { isDarkTheme } = this.props; const { isDarkTheme } = this.props;
return ( return (
<View style={[globalStyles.containerHorizontal16, { height: Math.max(maxHeight, height) }]}> <View style={[globalStyles.containerHorizontal16, { height: Math.max(maxHeight, height) }]}>
<TextInput <TextInput
style={[styles.textInput, { height: Math.max(maxHeight, height) }]} style={[styles.textInput, { height: Math.max(maxHeight, height) }]}
placeholderTextColor={isDarkTheme ? '#526d91' : '#c1c5c7'} placeholderTextColor={isDarkTheme ? '#526d91' : '#c1c5c7'}
@ -71,19 +69,13 @@ class TitleAreaView extends Component {
onChangeText={(textT) => this._handleOnChange(textT)} onChangeText={(textT) => this._handleOnChange(textT)}
value={text} value={text}
/> />
</View> </View>
); );
} }
} }
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
isDarkTheme: state.application.isDarkTheme, isDarkTheme: state.application.isDarkTheme,
}); });
export default connect(mapStateToProps)(TitleAreaView); export default connect(mapStateToProps)(TitleAreaView);

View File

@ -13,6 +13,7 @@ import FastImage from 'react-native-fast-image';
import Popover, { usePopover } from 'react-native-modal-popover'; import Popover, { usePopover } from 'react-native-modal-popover';
// Components // Components
import { useSelector } from 'react-redux';
import { TextInput } from '../../textInput'; import { TextInput } from '../../textInput';
import { Icon } from '../../icon'; import { Icon } from '../../icon';
// Utils // Utils
@ -20,7 +21,6 @@ import { getResizedAvatar } from '../../../utils/image';
// Styles // Styles
import styles from './formInputStyles'; import styles from './formInputStyles';
import { useSelector } from 'react-redux';
interface Props extends TextInputProps { interface Props extends TextInputProps {
type: string; type: string;
@ -133,7 +133,7 @@ const FormInputView = ({
const _renderInfoIconWithPopover = () => ( const _renderInfoIconWithPopover = () => (
<View style={styles.infoIconContainer}> <View style={styles.infoIconContainer}>
<TouchableOpacity ref={touchableRef} onPress={_handleInfoPress}> <TouchableOpacity ref={touchableRef} onPress={_handleInfoPress}>
<Icon iconType={'MaterialIcons'} name="info-outline" style={styles.infoIcon} /> <Icon iconType="MaterialIcons" name="info-outline" style={styles.infoIcon} />
</TouchableOpacity> </TouchableOpacity>
<Popover <Popover
backgroundStyle={styles.overlay} backgroundStyle={styles.overlay}

View File

@ -34,7 +34,6 @@ const HeaderContainer = ({ selectedUser, isReverse, handleOnBackPress, hideUser,
}; };
return ( return (
<AccountContainer> <AccountContainer>
{({ currentAccount, isLoggedIn, isLoginDone }) => { {({ currentAccount, isLoggedIn, isLoginDone }) => {
const _user = isReverse && selectedUser ? selectedUser : currentAccount; const _user = isReverse && selectedUser ? selectedUser : currentAccount;
@ -58,7 +57,6 @@ const HeaderContainer = ({ selectedUser, isReverse, handleOnBackPress, hideUser,
); );
}} }}
</AccountContainer> </AccountContainer>
); );
}; };

View File

@ -4,6 +4,7 @@ import { Platform, Text, TouchableOpacity, View, ActivityIndicator } from 'react
import { renderPostBody } from '@ecency/render-helper'; import { renderPostBody } from '@ecency/render-helper';
import { ScrollView } from 'react-native-gesture-handler'; import { ScrollView } from 'react-native-gesture-handler';
import Clipboard from '@react-native-clipboard/clipboard'; import Clipboard from '@react-native-clipboard/clipboard';
import EStyleSheet from 'react-native-extended-stylesheet';
import { MainButton, PostBody, TextButton } from '..'; import { MainButton, PostBody, TextButton } from '..';
import styles from './insertLinkModalStyles'; import styles from './insertLinkModalStyles';
import TextInput from '../textInput'; import TextInput from '../textInput';
@ -12,7 +13,6 @@ import { isStringWebLink } from '../markdownEditor/children/formats/utils';
import applyWebLinkFormat from '../markdownEditor/children/formats/applyWebLinkFormat'; import applyWebLinkFormat from '../markdownEditor/children/formats/applyWebLinkFormat';
import getWindowDimensions from '../../utils/getWindowDimensions'; import getWindowDimensions from '../../utils/getWindowDimensions';
import Modal from '../modal'; import Modal from '../modal';
import EStyleSheet from 'react-native-extended-stylesheet';
interface InsertLinkModalProps { interface InsertLinkModalProps {
handleOnInsertLink: ({ handleOnInsertLink: ({
@ -78,7 +78,7 @@ export const InsertLinkModal = forwardRef(
const labelText = const labelText =
selectedUrlType === 2 ? url.split('/').pop() : selectedUrlType === 1 ? '' : label; selectedUrlType === 2 ? url.split('/').pop() : selectedUrlType === 1 ? '' : label;
applyWebLinkFormat({ applyWebLinkFormat({
item: { text: labelText, url: url }, item: { text: labelText, url },
text: '', text: '',
selection: { start: 0, end: 0 }, selection: { start: 0, end: 0 },
setTextAndSelection: _setFormattedTextAndSelection, setTextAndSelection: _setFormattedTextAndSelection,
@ -98,7 +98,7 @@ export const InsertLinkModal = forwardRef(
}; };
const _setFormattedTextAndSelection = ({ selection, text }) => { const _setFormattedTextAndSelection = ({ selection, text }) => {
setPreviewBody(renderPostBody(text, true, Platform.OS === 'ios' ? false : true)); setPreviewBody(renderPostBody(text, true, Platform.OS !== 'ios'));
setFormattedText(text); setFormattedText(text);
}; };
@ -127,7 +127,7 @@ export const InsertLinkModal = forwardRef(
setIsUrlValid(false); setIsUrlValid(false);
return; return;
} }
handleOnInsertLink({ snippetText: formattedText, selection: selection }); handleOnInsertLink({ snippetText: formattedText, selection });
setIsUrlValid(true); setIsUrlValid(true);
}; };
const _renderFloatingPanel = () => { const _renderFloatingPanel = () => {

View File

@ -1,272 +1,252 @@
import React, { useEffect, useState, useMemo } from 'react' import React, { useEffect, useState, useMemo } from 'react';
import { useIntl } from 'react-intl' import { useIntl } from 'react-intl';
import { View, Alert } from 'react-native' import { View, Alert } from 'react-native';
import { ProfileStats, StatsData } from './profileStats' import { ProfileStats, StatsData } from './profileStats';
import { MainButton } from '../../..' import { MainButton } from '../../..';
import { addFavorite, checkFavorite, deleteFavorite } from '../../../../providers/ecency/ecency' import { addFavorite, checkFavorite, deleteFavorite } from '../../../../providers/ecency/ecency';
import { followUser, getFollows, getRelationship, getUser } from '../../../../providers/hive/dhive' import { followUser, getFollows, getRelationship, getUser } from '../../../../providers/hive/dhive';
import { getRcPower, getVotingPower } from '../../../../utils/manaBar' import { getRcPower, getVotingPower } from '../../../../utils/manaBar';
import styles from './quickProfileStyles' import styles from './quickProfileStyles';
import { ProfileBasic } from './profileBasic' import { ProfileBasic } from './profileBasic';
import { parseReputation } from '../../../../utils/user' import { parseReputation } from '../../../../utils/user';
import { default as ROUTES } from '../../../../constants/routeNames'; import { default as ROUTES } from '../../../../constants/routeNames';
import { ActionPanel } from './actionPanel' import { ActionPanel } from './actionPanel';
import { getTimeFromNowNative } from '../../../../utils/time' import { getTimeFromNowNative } from '../../../../utils/time';
import { useAppDispatch, useAppSelector } from '../../../../hooks' import { useAppDispatch, useAppSelector } from '../../../../hooks';
import { toastNotification } from '../../../../redux/actions/uiAction' import { toastNotification } from '../../../../redux/actions/uiAction';
import bugsnapInstance from '../../../../config/bugsnag' import bugsnapInstance from '../../../../config/bugsnag';
import RootNavigation from '../../../../navigation/rootNavigation' import RootNavigation from '../../../../navigation/rootNavigation';
interface QuickProfileContentProps { interface QuickProfileContentProps {
username: string, username: string;
onClose: () => void; onClose: () => void;
} }
export const QuickProfileContent = ({ export const QuickProfileContent = ({ username, onClose }: QuickProfileContentProps) => {
username, const intl = useIntl();
onClose const dispatch = useAppDispatch();
}: QuickProfileContentProps) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const currentAccount = useAppSelector((state) => state.account.currentAccount); const currentAccount = useAppSelector((state) => state.account.currentAccount);
const pinCode = useAppSelector((state) => state.application.pin); const pinCode = useAppSelector((state) => state.application.pin);
const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn); const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [user, setUser] = useState(null); const [user, setUser] = useState(null);
const [follows, setFollows] = useState(null); const [follows, setFollows] = useState(null);
const [isFollowing, setIsFollowing] = useState(false); const [isFollowing, setIsFollowing] = useState(false);
const [isMuted, setIsMuted] = useState(false); const [isMuted, setIsMuted] = useState(false);
const [isFavourite, setIsFavourite] = useState(false); const [isFavourite, setIsFavourite] = useState(false);
const isOwnProfile = currentAccount && currentAccount.name === username; const isOwnProfile = currentAccount && currentAccount.name === username;
const currentAccountName = currentAccount ? currentAccount.name : null; const currentAccountName = currentAccount ? currentAccount.name : null;
const isProfileLoaded = (user && follows) ? true : false; const isProfileLoaded = !!(user && follows);
useEffect(() => { useEffect(() => {
if (username) { if (username) {
_fetchUser(); _fetchUser();
_fetchExtraUserData(); _fetchExtraUserData();
} else { } else {
setUser(null); setUser(null);
}
}, [username]);
// NETWORK CALLS
const _fetchUser = async () => {
setIsLoading(true);
try {
const _user = await getUser(username, isOwnProfile);
setUser(_user);
} catch (error) {
setIsLoading(false);
}
};
const _fetchExtraUserData = async () => {
try {
if (username) {
let _isFollowing;
let _isMuted;
let _isFavourite;
let follows;
if (!isOwnProfile) {
const res = await getRelationship(currentAccountName, username);
_isFollowing = res && res.follows;
_isMuted = res && res.ignores;
_isFavourite = await checkFavorite(username);
} }
}, [username])
//NETWORK CALLS
const _fetchUser = async () => {
setIsLoading(true);
try { try {
const _user = await getUser(username, isOwnProfile); follows = await getFollows(username);
setUser(_user) } catch (err) {
} catch (error) { follows = null;
setIsLoading(false);
} }
setFollows(follows);
setIsFollowing(_isFollowing);
setIsMuted(_isMuted);
setIsFavourite(_isFavourite);
setIsLoading(false);
}
} catch (error) {
console.warn('Failed to fetch complete profile data', error);
Alert.alert(
intl.formatMessage({
id: 'alert.fail',
}),
error.message || error.toString(),
);
setIsLoading(false);
}
};
const _onFollowPress = async () => {
try {
const follower = currentAccountName;
const following = username;
setIsLoading(true);
await followUser(currentAccount, pinCode, {
follower,
following,
});
setIsLoading(false);
setIsFollowing(true);
dispatch(
toastNotification(
intl.formatMessage({
id: isFollowing ? 'alert.success_unfollow' : 'alert.success_follow',
}),
),
);
} catch (err) {
setIsLoading(false);
console.warn('Failed to follow user', err);
bugsnapInstance.notify(err);
Alert.alert(intl.formatMessage({ id: 'alert.fail' }), err.message);
}
};
const _onFavouritePress = async () => {
try {
setIsLoading(true);
let favoriteAction;
if (isFavourite) {
favoriteAction = deleteFavorite;
} else {
favoriteAction = addFavorite;
}
await favoriteAction(username);
dispatch(
toastNotification(
intl.formatMessage({
id: isFavourite ? 'alert.success_unfavorite' : 'alert.success_favorite',
}),
),
);
setIsFavourite(!isFavourite);
setIsLoading(false);
} catch (error) {
console.warn('Failed to perform favorite action');
setIsLoading(false);
Alert.alert(
intl.formatMessage({
id: 'alert.fail',
}),
error.message || error.toString(),
);
}
};
// UI CALLBACKS
const _openFullProfile = () => {
const params = {
username,
reputation: user ? user.reputation : null,
}; };
RootNavigation.navigate({
name: ROUTES.SCREENS.PROFILE,
params,
key: username,
});
const _fetchExtraUserData = async () => { if (onClose) {
try { onClose();
if (username) {
let _isFollowing;
let _isMuted;
let _isFavourite;
let follows;
if (!isOwnProfile) {
const res = await getRelationship(currentAccountName, username);
_isFollowing = res && res.follows;
_isMuted = res && res.ignores;
_isFavourite = await checkFavorite(username);
}
try {
follows = await getFollows(username);
} catch (err) {
follows = null;
}
setFollows(follows);
setIsFollowing(_isFollowing);
setIsMuted(_isMuted)
setIsFavourite(_isFavourite)
setIsLoading(false);
}
} catch (error) {
console.warn('Failed to fetch complete profile data', error);
Alert.alert(
intl.formatMessage({
id: 'alert.fail',
}),
error.message || error.toString(),
);
setIsLoading(false);
}
};
const _onFollowPress = async () => {
try {
const follower = currentAccountName
const following = username;
setIsLoading(true);
await followUser(currentAccount, pinCode, {
follower,
following,
})
setIsLoading(false);
setIsFollowing(true)
dispatch(
toastNotification(
intl.formatMessage({
id: isFollowing ? 'alert.success_unfollow' : 'alert.success_follow',
}),
),
);
}
catch (err) {
setIsLoading(false);
console.warn("Failed to follow user", err)
bugsnapInstance.notify(err);
Alert.alert(intl.formatMessage({ id: 'alert.fail' }), err.message)
}
} }
};
const _onFavouritePress = async () => { // extract prop values
try { let _votingPower = '';
setIsLoading(true); let _resourceCredits = '';
let favoriteAction; let _followerCount = 0;
let _followingCount = 0;
let _postCount = 0;
let _about = '';
let _reputation = 0;
let _createdData = null;
if (isFavourite) { if (isProfileLoaded) {
favoriteAction = deleteFavorite; _votingPower = getVotingPower(user).toFixed(1);
} else { _resourceCredits = getRcPower(user).toFixed(0);
favoriteAction = addFavorite; _postCount = user.post_count || 0;
} _about = user.about?.profile?.about || '';
_reputation = parseReputation(user.reputation);
_createdData = getTimeFromNowNative(user.created);
await favoriteAction(username) if (follows) {
_followerCount = follows.follower_count || 0;
dispatch( _followingCount = follows.following_count || 0;
toastNotification(
intl.formatMessage({
id: isFavourite ? 'alert.success_unfavorite' : 'alert.success_favorite',
}),
),
);
setIsFavourite(!isFavourite);
setIsLoading(false);
}
catch (error) {
console.warn('Failed to perform favorite action');
setIsLoading(false);
Alert.alert(
intl.formatMessage({
id: 'alert.fail',
}),
error.message || error.toString(),
);
}
} }
}
const statsData1 = [
{ label: intl.formatMessage({ id: 'profile.follower' }), value: _followerCount },
{ label: intl.formatMessage({ id: 'profile.following' }), value: _followingCount },
{ label: intl.formatMessage({ id: 'profile.post' }), value: _postCount },
] as StatsData[];
const statsData2 = [
{
label: intl.formatMessage({ id: 'profile.resource_credits' }),
value: _resourceCredits,
suffix: '%',
},
{ label: intl.formatMessage({ id: 'profile.reputation' }), value: _reputation },
] as StatsData[];
//UI CALLBACKS return (
<View style={styles.modalStyle}>
const _openFullProfile = () => { <ProfileBasic
let params = { username={username}
username, about={_about}
reputation: user ? user.reputation : null created={_createdData}
}; votingPower={_votingPower}
isLoading={isLoading}
onPress={_openFullProfile}
RootNavigation.navigate({ />
name: ROUTES.SCREENS.PROFILE, <ProfileStats data={statsData1} intermediate={!isProfileLoaded} />
params, <ProfileStats horizontalMargin={16} data={statsData2} intermediate={!isProfileLoaded} />
key: username, <MainButton
}); style={styles.button}
text={intl.formatMessage({ id: 'profile.view_full' })}
if (onClose) { onPress={_openFullProfile}
onClose(); />
} {isLoggedIn && (
} <ActionPanel
isFollowing={isFollowing}
//extract prop values isFavourite={isFavourite}
let _votingPower = ''; isMuted={isMuted}
let _resourceCredits = ''; isLoading={isLoading}
let _followerCount = 0; onFavouritePress={_onFavouritePress}
let _followingCount = 0; onFollowPress={_onFollowPress}
let _postCount = 0; />
let _about = ''; )}
let _reputation = 0; </View>
let _createdData = null; );
if (isProfileLoaded) {
_votingPower = getVotingPower(user).toFixed(1);
_resourceCredits = getRcPower(user).toFixed(0);
_postCount = user.post_count || 0;
_about = user.about?.profile?.about || '';
_reputation = parseReputation(user.reputation);
_createdData = getTimeFromNowNative(user.created)
if (follows) {
_followerCount = follows.follower_count || 0;
_followingCount = follows.following_count || 0
}
}
const statsData1 = [
{ label: intl.formatMessage({ id: 'profile.follower' }), value: _followerCount },
{ label: intl.formatMessage({ id: 'profile.following' }), value: _followingCount },
{ label: intl.formatMessage({ id: 'profile.post' }), value: _postCount },
] as StatsData[]
const statsData2 = [
{ label: intl.formatMessage({ id: 'profile.resource_credits' }), value: _resourceCredits, suffix: '%' },
{ label: intl.formatMessage({ id: 'profile.reputation' }), value: _reputation },
] as StatsData[]
return (
<View style={styles.modalStyle}>
<ProfileBasic
username={username}
about={_about}
created={_createdData}
votingPower={_votingPower}
isLoading={isLoading}
onPress={_openFullProfile}
/>
<ProfileStats
data={statsData1}
intermediate={!isProfileLoaded}
/>
<ProfileStats
horizontalMargin={16}
data={statsData2}
intermediate={!isProfileLoaded}
/>
<MainButton
style={styles.button}
text={intl.formatMessage({ id: 'profile.view_full' })}
onPress={_openFullProfile}
/>
{isLoggedIn && (
<ActionPanel
isFollowing={isFollowing}
isFavourite={isFavourite}
isMuted={isMuted}
isLoading={isLoading}
onFavouritePress={_onFavouritePress}
onFollowPress={_onFollowPress}
/>
)}
</View>
)
}; };

View File

@ -3,102 +3,98 @@ import EStyleSheet from 'react-native-extended-stylesheet';
import { getBottomSpace } from 'react-native-iphone-x-helper'; import { getBottomSpace } from 'react-native-iphone-x-helper';
export default EStyleSheet.create({ export default EStyleSheet.create({
modalStyle: { modalStyle: {
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
margin:0, margin: 0,
paddingTop:32, paddingTop: 32,
marginHorizontal:24, marginHorizontal: 24,
paddingBottom: getBottomSpace() + 8, paddingBottom: getBottomSpace() + 8,
}, },
sheetContent: { sheetContent: {
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
}, },
container:{ container: {
alignItems:'center', alignItems: 'center',
marginHorizontal:16 marginHorizontal: 16,
} as ViewStyle, } as ViewStyle,
image:{ image: {
width:128, width: 128,
height:128, height: 128,
borderRadius:64, borderRadius: 64,
backgroundColor: '$primaryGray' backgroundColor: '$primaryGray',
} as ImageStyle, } as ImageStyle,
textContainer:{ textContainer: {
marginTop:32, marginTop: 32,
marginBottom:44, marginBottom: 44,
} as ViewStyle, } as ViewStyle,
title: { title: {
color: '$primaryBlack', color: '$primaryBlack',
alignSelf: 'center', alignSelf: 'center',
textAlign: 'center', textAlign: 'center',
fontSize: 18, fontSize: 18,
fontWeight: 'bold', fontWeight: 'bold',
marginTop:32, marginTop: 32,
} as TextStyle, } as TextStyle,
statValue: { statValue: {
fontFamily:'$editorFont', fontFamily: '$editorFont',
color: '$primaryBlack', color: '$primaryBlack',
alignSelf: 'center', alignSelf: 'center',
textAlign: 'center', textAlign: 'center',
fontSize: 34, fontSize: 34,
fontWeight: 'normal', fontWeight: 'normal',
} as TextStyle, } as TextStyle,
statLabel: { statLabel: {
color: '$primaryBlack', color: '$primaryBlack',
alignSelf: 'center', alignSelf: 'center',
textAlign: 'center', textAlign: 'center',
fontSize: 16, fontSize: 16,
fontWeight: 'normal', fontWeight: 'normal',
} as TextStyle, } as TextStyle,
bodyText: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 18,
marginTop: 6,
} as TextStyle,
bodyText: { btnText: {
color: '$primaryBlack', color: '$pureWhite',
alignSelf: 'center', } as TextStyle,
textAlign: 'center',
fontSize: 18,
marginTop:6,
} as TextStyle,
button: {
marginTop: 40,
backgroundColor: '$primaryBlue',
paddingHorizontal: 44,
paddingVertical: 16,
borderRadius: 32,
justifyContent: 'center',
alignItems: 'center',
} as ViewStyle,
btnText:{ actionPanel: {
color:'$pureWhite' position: 'absolute',
} as TextStyle, right: 0,
top: 0,
flexDirection: 'row',
alignItems: 'center',
} as ViewStyle,
button:{ progressCircle: {
marginTop: 40, position: 'absolute',
backgroundColor:'$primaryBlue', top: 0,
paddingHorizontal:44, bottom: 0,
paddingVertical:16, left: 0,
borderRadius:32, right: 0,
justifyContent:'center', alignItems: 'center',
alignItems:'center' justifyContent: 'center',
} as ViewStyle, } as ViewStyle,
});
actionPanel:{
position: 'absolute',
right:0,
top:0,
flexDirection:'row',
alignItems:'center',
} as ViewStyle,
progressCircle:{
position:'absolute',
top:0,
bottom:0,
left:0,
right:0,
alignItems:'center',
justifyContent:'center'
} as ViewStyle
})

View File

@ -1,123 +1,105 @@
import React, { Fragment, useCallback, useEffect, useRef, useState } from "react"; import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react';
import { findNodeHandle, NativeModules, View, TouchableOpacity, Text, Alert } from "react-native"; import { findNodeHandle, NativeModules, View, TouchableOpacity, Text, Alert } from 'react-native';
import { useAppSelector } from "../../../hooks"; import { Rect } from 'react-native-modal-popover/lib/PopoverGeometry';
import { PulseAnimation } from "../../animations"; import { useAppSelector } from '../../../hooks';
import { PulseAnimation } from '../../animations';
import { isVoted as isVotedFunc, isDownVoted as isDownVotedFunc } from '../../../utils/postParser'; import { isVoted as isVotedFunc, isDownVoted as isDownVotedFunc } from '../../../utils/postParser';
import Icon from "../../icon"; import Icon from '../../icon';
import styles from './children.styles'; import styles from './children.styles';
import { FormattedCurrency } from "../../formatedElements"; import { FormattedCurrency } from '../../formatedElements';
import { Rect } from "react-native-modal-popover/lib/PopoverGeometry"; import { PostTypes } from '../../../constants/postTypes';
import { PostTypes } from "../../../constants/postTypes";
interface UpvoteButtonProps { interface UpvoteButtonProps {
content: any, content: any;
activeVotes: any[], activeVotes: any[];
isShowPayoutValue?: boolean, isShowPayoutValue?: boolean;
boldPayout?: boolean, boldPayout?: boolean;
parentType?: PostTypes; parentType?: PostTypes;
onUpvotePress: (anchorRect: Rect, onVotingStart: (status:number)=>void) => void, onUpvotePress: (anchorRect: Rect, onVotingStart: (status: number) => void) => void;
onPayoutDetailsPress: (anchorRef: Rect) => void, onPayoutDetailsPress: (anchorRef: Rect) => void;
} }
export const UpvoteButton = ({ export const UpvoteButton = ({
content, content,
activeVotes, activeVotes,
isShowPayoutValue, isShowPayoutValue,
boldPayout, boldPayout,
onUpvotePress, onUpvotePress,
onPayoutDetailsPress onPayoutDetailsPress,
}: UpvoteButtonProps) => { }: UpvoteButtonProps) => {
const upvoteRef = useRef(null);
const detailsRef = useRef(null);
const upvoteRef = useRef(null); const currentAccount = useAppSelector((state) => state.account.currentAccount);
const detailsRef = useRef(null);
const currentAccount = useAppSelector((state => state.account.currentAccount)); const [isVoted, setIsVoted] = useState<any>(null);
const [isDownVoted, setIsDownVoted] = useState<any>(null);
const [isVoted, setIsVoted] = useState<any>(null); useEffect(() => {
const [isDownVoted, setIsDownVoted] = useState<any>(null); _calculateVoteStatus();
}, [activeVotes]);
const _calculateVoteStatus = useCallback(async () => {
// TODO: do this heavy lifting during parsing or react-query/cache response
const _isVoted = await isVotedFunc(activeVotes, currentAccount?.name);
const _isDownVoted = await isDownVotedFunc(activeVotes, currentAccount?.name);
useEffect(() => { setIsVoted(_isVoted && parseInt(_isVoted, 10) / 10000);
setIsDownVoted(_isDownVoted && (parseInt(_isDownVoted, 10) / 10000) * -1);
}, [activeVotes]);
const _getRectFromRef = (ref: any, callback: (anchorRect: Rect, onVotingStart?) => void) => {
const handle = findNodeHandle(ref.current);
if (handle) {
NativeModules.UIManager.measure(handle, (x0, y0, width, height, x, y) => {
const anchorRect: Rect = { x, y, width, height };
callback(anchorRect);
});
}
};
const _onPress = () => {
const _onVotingStart = (status) => {
if (status > 0) {
setIsVoted(true);
} else if (status < 0) {
setIsDownVoted(true);
} else {
_calculateVoteStatus(); _calculateVoteStatus();
}, [activeVotes]); }
};
_getRectFromRef(upvoteRef, (rect) => {
onUpvotePress(rect, _onVotingStart);
});
};
const _onDetailsPress = () => {
_getRectFromRef(detailsRef, onPayoutDetailsPress);
};
const _calculateVoteStatus = useCallback(async () => { const isDeclinedPayout = content?.is_declined_payout;
const totalPayout = content?.total_payout;
const maxPayout = content?.max_payout;
//TODO: do this heavy lifting during parsing or react-query/cache response const payoutLimitHit = totalPayout >= maxPayout;
const _isVoted = await isVotedFunc(activeVotes, currentAccount?.name); const _shownPayout = payoutLimitHit && maxPayout > 0 ? maxPayout : totalPayout;
const _isDownVoted = await isDownVotedFunc(activeVotes, currentAccount?.name);
let iconName = 'upcircleo';
setIsVoted(_isVoted && parseInt(_isVoted, 10) / 10000); const iconType = 'AntDesign';
setIsDownVoted(_isDownVoted && (parseInt(_isDownVoted, 10) / 10000) * -1); let downVoteIconName = 'downcircleo';
}, [activeVotes]);
if (isVoted) {
iconName = 'upcircle';
}
const _getRectFromRef = (ref: any, callback: (anchorRect: Rect, onVotingStart?) => void) => { if (isDownVoted) {
const handle = findNodeHandle(ref.current); downVoteIconName = 'downcircle';
if (handle) { }
NativeModules.UIManager.measure(handle, (x0, y0, width, height, x, y) => {
const anchorRect: Rect = { x, y, width, height };
callback(anchorRect)
});
}
}
return (
const _onPress = () => { <View style={styles.container}>
const _onVotingStart = (status) => { <TouchableOpacity ref={upvoteRef} onPress={_onPress} style={styles.upvoteButton}>
if(status > 0){ {/* <Fragment>
setIsVoted(true);
} else if (status < 0) {
setIsDownVoted(true);
} else {
_calculateVoteStatus();
}
}
_getRectFromRef(upvoteRef, (rect)=>{
onUpvotePress(rect, _onVotingStart)
});
}
const _onDetailsPress = () => {
_getRectFromRef(detailsRef, onPayoutDetailsPress)
}
const isDeclinedPayout = content?.is_declined_payout;
const totalPayout = content?.total_payout;
const maxPayout = content?.max_payout;
const payoutLimitHit = totalPayout >= maxPayout;
const _shownPayout = payoutLimitHit && maxPayout > 0 ? maxPayout : totalPayout;
let iconName = 'upcircleo';
const iconType = 'AntDesign';
let downVoteIconName = 'downcircleo';
if (isVoted) {
iconName = 'upcircle';
}
if (isDownVoted) {
downVoteIconName = 'downcircle';
}
return (
<View style={styles.container}>
<TouchableOpacity
ref={upvoteRef}
onPress={_onPress}
style={styles.upvoteButton}
>
{/* <Fragment>
{isVoting ? ( {isVoting ? (
<View style={{ width: 19 }}> <View style={{ width: 19 }}>
<PulseAnimation <PulseAnimation
@ -130,34 +112,32 @@ export const UpvoteButton = ({
/> />
</View> </View>
) : ( */} ) : ( */}
<View hitSlop={{ top: 10, bottom: 10, left: 10, right: 5 }}> <View hitSlop={{ top: 10, bottom: 10, left: 10, right: 5 }}>
<Icon <Icon
style={[styles.upvoteIcon, isDownVoted && { color: '#ec8b88' }]} style={[styles.upvoteIcon, isDownVoted && { color: '#ec8b88' }]}
active={!currentAccount} active={!currentAccount}
iconType={iconType} iconType={iconType}
name={isDownVoted ? downVoteIconName : iconName} name={isDownVoted ? downVoteIconName : iconName}
/> />
</View>
{/* )}
</Fragment> */}
</TouchableOpacity>
<View style={styles.payoutTextButton}>
{isShowPayoutValue && (
<TouchableOpacity ref={detailsRef} onPress={_onDetailsPress} >
<Text
style={[
styles.payoutValue,
isDeclinedPayout && styles.declinedPayout,
boldPayout && styles.boldText,
]}
>
{<FormattedCurrency value={_shownPayout || '0.000'} />}
</Text>
</TouchableOpacity>
)}
</View>
</View> </View>
{/* )}
) </Fragment> */}
} </TouchableOpacity>
<View style={styles.payoutTextButton}>
{isShowPayoutValue && (
<TouchableOpacity ref={detailsRef} onPress={_onDetailsPress}>
<Text
style={[
styles.payoutValue,
isDeclinedPayout && styles.declinedPayout,
boldPayout && styles.boldText,
]}
>
<FormattedCurrency value={_shownPayout || '0.000'} />
</Text>
</TouchableOpacity>
)}
</View>
</View>
);
};

View File

@ -15,12 +15,15 @@ export const CommentsSection = ({ item, index, revealReplies, ...props }) => {
const _renderComment = (item, index = 0) => { const _renderComment = (item, index = 0) => {
// animation makes sure there is 100 ms gab between each comment item // animation makes sure there is 100 ms gab between each comment item
const _enteringAnim = index >= 0 const _enteringAnim =
? SlideInRight.duration(150).springify().delay(index * 100) index >= 0
: undefined ? SlideInRight.duration(150)
.springify()
.delay(index * 100)
: undefined;
return ( return (
<Animated.View key={item.author + item.permlink} entering={_enteringAnim}> <Animated.View key={item.author + item.permlink} entering={_enteringAnim}>
<Comment <Comment
comment={item} comment={item}
repliesToggle={toggle} repliesToggle={toggle}

View File

@ -21,7 +21,11 @@ import { FilterBar } from '../../filterBar';
import { postQueries } from '../../../providers/queries'; import { postQueries } from '../../../providers/queries';
import { useAppDispatch, useAppSelector } from '../../../hooks'; import { useAppDispatch, useAppSelector } from '../../../hooks';
import ROUTES from '../../../constants/routeNames'; import ROUTES from '../../../constants/routeNames';
import { showActionModal, showProfileModal, toastNotification } from '../../../redux/actions/uiAction'; import {
showActionModal,
showProfileModal,
toastNotification,
} from '../../../redux/actions/uiAction';
import { writeToClipboard } from '../../../utils/clipboard'; import { writeToClipboard } from '../../../utils/clipboard';
import { deleteComment } from '../../../providers/hive/dhive'; import { deleteComment } from '../../../providers/hive/dhive';
import { updateCommentCache } from '../../../redux/actions/cacheActions'; import { updateCommentCache } from '../../../redux/actions/cacheActions';
@ -34,8 +38,6 @@ import { sortComments } from '../children/sortComments';
import styles from '../children/postComments.styles'; import styles from '../children/postComments.styles';
import { PostHtmlInteractionHandler } from '../../postHtmlRenderer'; import { PostHtmlInteractionHandler } from '../../postHtmlRenderer';
const PostComments = forwardRef( const PostComments = forwardRef(
( (
{ {
@ -47,7 +49,7 @@ const PostComments = forwardRef(
onRefresh, onRefresh,
handleOnCommentsLoaded, handleOnCommentsLoaded,
handleOnReplyPress, handleOnReplyPress,
onUpvotePress onUpvotePress,
}, },
ref, ref,
) => { ) => {
@ -63,7 +65,7 @@ const PostComments = forwardRef(
const postsCachePrimer = postQueries.usePostsCachePrimer(); const postsCachePrimer = postQueries.usePostsCachePrimer();
const writeCommentRef = useRef(null); const writeCommentRef = useRef(null);
const postInteractionRef = useRef<typeof PostHtmlInteractionHandler|null>(null); const postInteractionRef = useRef<typeof PostHtmlInteractionHandler | null>(null);
const commentsListRef = useRef<FlashList<any> | null>(null); const commentsListRef = useRef<FlashList<any> | null>(null);
const [selectedFilter, setSelectedFilter] = useState('trending'); const [selectedFilter, setSelectedFilter] = useState('trending');
@ -72,7 +74,6 @@ const PostComments = forwardRef(
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const sortedSections = useMemo( const sortedSections = useMemo(
() => sortComments(selectedFilter, discussionQuery.sectionedData), () => sortComments(selectedFilter, discussionQuery.sectionedData),
[discussionQuery.sectionedData, selectedFilter], [discussionQuery.sectionedData, selectedFilter],
@ -107,9 +108,6 @@ const PostComments = forwardRef(
onRefresh(); onRefresh();
}; };
const _handleOnDropdownSelect = (option, index) => { const _handleOnDropdownSelect = (option, index) => {
setSelectedFilter(option); setSelectedFilter(option);
setSelectedOptionIndex(index); setSelectedOptionIndex(index);
@ -139,7 +137,6 @@ const PostComments = forwardRef(
}; };
const _handleDeleteComment = (_permlink) => { const _handleDeleteComment = (_permlink) => {
const _onConfirmDelete = async () => { const _onConfirmDelete = async () => {
try { try {
await deleteComment(currentAccount, pinHash, _permlink); await deleteComment(currentAccount, pinHash, _permlink);
@ -154,23 +151,27 @@ const PostComments = forwardRef(
dispatch(updateCommentCache(_commentPath, _deletedItem, { isUpdate: true })); dispatch(updateCommentCache(_commentPath, _deletedItem, { isUpdate: true }));
} }
} catch (err) { } catch (err) {
console.warn('Failed to delete comment') console.warn('Failed to delete comment');
} }
};
} dispatch(
showActionModal({
dispatch(showActionModal({ title: intl.formatMessage({ id: 'delete.confirm_delete_title' }),
title: intl.formatMessage({ id: 'delete.confirm_delete_title' }), buttons: [
buttons: [{ {
text: intl.formatMessage({ id: 'alert.cancel' }), text: intl.formatMessage({ id: 'alert.cancel' }),
onPress: () => { console.log("canceled delete comment") } onPress: () => {
}, { console.log('canceled delete comment');
text: intl.formatMessage({ id: 'alert.delete' }), },
onPress: _onConfirmDelete },
}] {
})) text: intl.formatMessage({ id: 'alert.delete' }),
onPress: _onConfirmDelete,
},
],
}),
);
}; };
const _openReplyThread = (comment) => { const _openReplyThread = (comment) => {
@ -187,7 +188,7 @@ const PostComments = forwardRef(
const _handleOnUserPress = (username) => { const _handleOnUserPress = (username) => {
dispatch(showProfileModal(username)); dispatch(showProfileModal(username));
} };
const _handleShowOptionsMenu = (comment) => { const _handleShowOptionsMenu = (comment) => {
const _showCopiedToast = () => { const _showCopiedToast = () => {
@ -231,11 +232,6 @@ const PostComments = forwardRef(
); );
}; };
const _onContentSizeChange = (x: number, y: number) => { const _onContentSizeChange = (x: number, y: number) => {
// update header height // update header height
if (y !== headerHeight) { if (y !== headerHeight) {
@ -243,8 +239,6 @@ const PostComments = forwardRef(
} }
}; };
const _postContentView = ( const _postContentView = (
<> <>
{postContentView && postContentView} {postContentView && postContentView}
@ -263,8 +257,7 @@ const PostComments = forwardRef(
); );
const _renderEmptyContent = () => { const _renderEmptyContent = () => {
if (isPostLoading) {
if(isPostLoading){
return null; return null;
} }
@ -303,10 +296,8 @@ const PostComments = forwardRef(
openReplyThread={_openReplyThread} openReplyThread={_openReplyThread}
onUpvotePress={(args) => onUpvotePress({ ...args, postType: PostTypes.COMMENT })} onUpvotePress={(args) => onUpvotePress({ ...args, postType: PostTypes.COMMENT })}
/> />
) );
} };
return ( return (
<Fragment> <Fragment>
@ -333,14 +324,10 @@ const PostComments = forwardRef(
} }
overScrollMode="never" overScrollMode="never"
/> />
<PostHtmlInteractionHandler <PostHtmlInteractionHandler ref={postInteractionRef} />
ref={postInteractionRef}
/>
</Fragment> </Fragment>
); );
}, },
); );
export default PostComments; export default PostComments;

View File

@ -101,7 +101,6 @@ const CommentBody = ({
} }
}; };
const _handleOnUserPress = (username) => { const _handleOnUserPress = (username) => {
if (handleOnUserPress) { if (handleOnUserPress) {
handleOnUserPress(username); handleOnUserPress(username);

View File

@ -50,7 +50,7 @@ export const PostHtmlRenderer = memo(
body = body body = body
.replace(/<center>/g, '<div class="text-center">') .replace(/<center>/g, '<div class="text-center">')
.replace(/<\/center>/g, '</div>') .replace(/<\/center>/g, '</div>')
.replace(/<span(.*?)>/g, '') //TODO: later handle span with propties lie <span class="ll-key"> and remove on raw <span/> .replace(/<span(.*?)>/g, '') // TODO: later handle span with propties lie <span class="ll-key"> and remove on raw <span/>
.replace(/<\/span>/g, ''); .replace(/<\/span>/g, '');
const _minTableColWidth = contentWidth / 3 - 12; const _minTableColWidth = contentWidth / 3 - 12;
@ -277,7 +277,6 @@ export const PostHtmlRenderer = memo(
const _paraRenderer = ({ TDefaultRenderer, ...props }: CustomRendererProps<TNode>) => { const _paraRenderer = ({ TDefaultRenderer, ...props }: CustomRendererProps<TNode>) => {
props.style = props.tnode.parent.tagName === 'li' ? styles.pLi : styles.p; props.style = props.tnode.parent.tagName === 'li' ? styles.pLi : styles.p;
props.onPress = !props.onPress && handleOnContentPress ? handleOnContentPress : props.onPress; props.onPress = !props.onPress && handleOnContentPress ? handleOnContentPress : props.onPress;
return <TDefaultRenderer {...props} />; return <TDefaultRenderer {...props} />;
}; };
@ -399,7 +398,7 @@ export const PostHtmlRenderer = memo(
customHTMLElementModels={customHTMLElementModels} customHTMLElementModels={customHTMLElementModels}
renderersProps={renderersProps} renderersProps={renderersProps}
WebView={WebView} WebView={WebView}
pressableHightlightColor={'transparent'} pressableHightlightColor="transparent"
/> />
); );
}, },

View File

@ -87,7 +87,7 @@ export default EStyleSheet.create({
color: '$primaryRed', color: '$primaryRed',
} as TextStyle, } as TextStyle,
textJustify: { textJustify: {
textAlign: Platform.select({ ios: 'justify', android: 'auto' }), //justify with selectable on android causes ends of text getting clipped, textAlign: Platform.select({ ios: 'justify', android: 'auto' }), // justify with selectable on android causes ends of text getting clipped,
letterSpacing: 0, letterSpacing: 0,
} as TextStyle, } as TextStyle,
revealButton: { revealButton: {

View File

@ -1,10 +1,4 @@
import React, { import React, { forwardRef, useImperativeHandle, useRef, useState, Fragment } from 'react';
forwardRef,
useImperativeHandle,
useRef,
useState,
Fragment,
} from 'react';
import { PermissionsAndroid, Platform, SafeAreaView, View, Text } from 'react-native'; import { PermissionsAndroid, Platform, SafeAreaView, View, Text } from 'react-native';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import ActionsSheet from 'react-native-actions-sheet'; import ActionsSheet from 'react-native-actions-sheet';
@ -12,29 +6,27 @@ import ImageView from 'react-native-image-viewing';
// Components // Components
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
import CameraRoll from '@react-native-community/cameraroll';
import RNFetchBlob from 'rn-fetch-blob';
import { useDispatch } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
import ROUTES from '../../constants/routeNames'; import ROUTES from '../../constants/routeNames';
import { toastNotification } from '../../redux/actions/uiAction'; import { toastNotification } from '../../redux/actions/uiAction';
import { writeToClipboard } from '../../utils/clipboard'; import { writeToClipboard } from '../../utils/clipboard';
import CameraRoll from '@react-native-community/cameraroll';
import RNFetchBlob from 'rn-fetch-blob';
import { OptionsModal } from '../atoms'; import { OptionsModal } from '../atoms';
import VideoPlayer from '../videoPlayer/videoPlayerView'; import VideoPlayer from '../videoPlayer/videoPlayerView';
import { useDispatch } from 'react-redux';
import { useNavigation } from '@react-navigation/native';
import { IconButton } from '../buttons'; import { IconButton } from '../buttons';
import styles from './postHtmlRendererStyles' import styles from './postHtmlRendererStyles';
import { PostTypes } from '../../constants/postTypes'; import { PostTypes } from '../../constants/postTypes';
interface PostHtmlInteractionHandlerProps { interface PostHtmlInteractionHandlerProps {
postType?:PostTypes postType?: PostTypes;
} }
export const PostHtmlInteractionHandler = forwardRef(({ export const PostHtmlInteractionHandler = forwardRef(
postType ({ postType }: PostHtmlInteractionHandlerProps, ref) => {
}:PostHtmlInteractionHandlerProps, ref) => {
const navigation = useNavigation(); const navigation = useNavigation();
const dispatch = useDispatch(); const dispatch = useDispatch();
const intl = useIntl(); const intl = useIntl();
@ -52,245 +44,240 @@ export const PostHtmlInteractionHandler = forwardRef(({
const [selectedImage, setSelectedImage] = useState(null); const [selectedImage, setSelectedImage] = useState(null);
const [selectedLink, setSelectedLink] = useState(null); const [selectedLink, setSelectedLink] = useState(null);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
handleImagePress: (url: string, postImgUrls: string[]) => { handleImagePress: (url: string, postImgUrls: string[]) => {
setPostImages(postImgUrls); setPostImages(postImgUrls);
setSelectedImage(url); setSelectedImage(url);
if(postType === PostTypes.WAVE){ if (postType === PostTypes.WAVE) {
setIsImageModalOpen(true); setIsImageModalOpen(true);
} else { } else {
actionImage.current?.show(); actionImage.current?.show();
}
},
handleLinkPress: (url: string) => {
setSelectedLink(url);
actionLink.current?.show();
},
handleYoutubePress: (videoId, startTime) => {
if (videoId && youtubePlayerRef.current) {
setYoutubeVideoId(videoId);
setVideoStartTime(startTime);
youtubePlayerRef.current.setModalVisible(true);
}
},
handleVideoPress: (embedUrl) => {
if (embedUrl && youtubePlayerRef.current) {
setVideoUrl(embedUrl);
setVideoStartTime(0);
youtubePlayerRef.current.setModalVisible(true);
}
} }
})) },
handleLinkPress: (url: string) => {
setSelectedLink(url);
actionLink.current?.show();
},
handleYoutubePress: (videoId, startTime) => {
if (videoId && youtubePlayerRef.current) {
setYoutubeVideoId(videoId);
setVideoStartTime(startTime);
youtubePlayerRef.current.setModalVisible(true);
}
},
handleVideoPress: (embedUrl) => {
if (embedUrl && youtubePlayerRef.current) {
setVideoUrl(embedUrl);
setVideoStartTime(0);
youtubePlayerRef.current.setModalVisible(true);
}
},
}));
const checkAndroidPermission = async () => { const checkAndroidPermission = async () => {
try { try {
const permission = PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE; const permission = PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE;
await PermissionsAndroid.request(permission); await PermissionsAndroid.request(permission);
Promise.resolve(); Promise.resolve();
} catch (error) { } catch (error) {
Promise.reject(error); Promise.reject(error);
} }
}; };
const _downloadImage = async (uri) => { const _downloadImage = async (uri) => {
return RNFetchBlob.config({ return RNFetchBlob.config({
fileCache: true, fileCache: true,
appendExt: 'jpg', appendExt: 'jpg',
}) })
.fetch('GET', uri) .fetch('GET', uri)
.then((res) => { .then((res) => {
const { status } = res.info(); const { status } = res.info();
if (status == 200) { if (status == 200) {
return res.path(); return res.path();
} else { } else {
Promise.reject(); Promise.reject();
} }
}) })
.catch((errorMessage) => { .catch((errorMessage) => {
Promise.reject(errorMessage); Promise.reject(errorMessage);
}); });
}; };
const _saveImage = async (uri) => { const _saveImage = async (uri) => {
try { try {
if (Platform.OS === 'android') { if (Platform.OS === 'android') {
await checkAndroidPermission(); await checkAndroidPermission();
uri = `file://${await _downloadImage(uri)}`; uri = `file://${await _downloadImage(uri)}`;
}
CameraRoll.saveToCameraRoll(uri)
.then(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved',
}),
),
);
})
.catch(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved_error',
}),
),
);
});
} catch (error) {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved_error',
}),
),
);
} }
CameraRoll.saveToCameraRoll(uri)
.then(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved',
}),
),
);
})
.catch(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved_error',
}),
),
);
});
} catch (error) {
dispatch(
toastNotification(
intl.formatMessage({
id: 'post.image_saved_error',
}),
),
);
}
}; };
const _handleImageOptionPress = (ind) => { const _handleImageOptionPress = (ind) => {
if (ind === 1) { if (ind === 1) {
// open gallery mode // open gallery mode
setIsImageModalOpen(true); setIsImageModalOpen(true);
} }
if (ind === 0) { if (ind === 0) {
// copy to clipboard // copy to clipboard
writeToClipboard(selectedImage).then(() => { writeToClipboard(selectedImage).then(() => {
dispatch( dispatch(
toastNotification( toastNotification(
intl.formatMessage({ intl.formatMessage({
id: 'alert.copied', id: 'alert.copied',
}), }),
), ),
); );
}); });
} }
if (ind === 2) { if (ind === 2) {
// save to local // save to local
_saveImage(selectedImage); _saveImage(selectedImage);
} }
setSelectedImage(null); setSelectedImage(null);
}; };
const _handleLinkOptionPress = (ind) => { const _handleLinkOptionPress = (ind) => {
if (ind === 1) { if (ind === 1) {
// open link // open link
if (selectedLink) { if (selectedLink) {
navigation.navigate({ navigation.navigate({
name: ROUTES.SCREENS.WEB_BROWSER, name: ROUTES.SCREENS.WEB_BROWSER,
params: { params: {
url: selectedLink, url: selectedLink,
}, },
key: selectedLink, key: selectedLink,
} as never); } as never);
}
}
if (ind === 0) {
// copy to clipboard
writeToClipboard(selectedLink).then(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'alert.copied',
}),
),
);
});
} }
}
if (ind === 0) {
// copy to clipboard
writeToClipboard(selectedLink).then(() => {
dispatch(
toastNotification(
intl.formatMessage({
id: 'alert.copied',
}),
),
);
});
}
setSelectedLink(null); setSelectedLink(null);
}; };
const _renderImageViewerHeader = (imageIndex) => { const _renderImageViewerHeader = (imageIndex) => {
return ( return (
<SafeAreaView <SafeAreaView
style={{ style={{
marginTop: Platform.select({ ios: 0, android: 25 }), marginTop: Platform.select({ ios: 0, android: 25 }),
}} }}
> >
<View style={styles.imageViewerHeaderContainer}> <View style={styles.imageViewerHeaderContainer}>
<Text style={styles.imageGalleryHeaderText}>{`${imageIndex + 1}/${ <Text style={styles.imageGalleryHeaderText}>{`${imageIndex + 1}/${
postImages.length postImages.length
}`}</Text> }`}</Text>
<IconButton <IconButton
name="close" name="close"
color={EStyleSheet.value('$primaryDarkText')} color={EStyleSheet.value('$primaryDarkText')}
buttonStyle={styles.closeIconButton} buttonStyle={styles.closeIconButton}
size={20} size={20}
handleOnPress={() => setIsImageModalOpen(false)} handleOnPress={() => setIsImageModalOpen(false)}
/> />
</View> </View>
</SafeAreaView> </SafeAreaView>
); );
}; };
return ( return (
<Fragment> <Fragment>
<ImageView <ImageView
images={postImages.map((url) => ({ uri: url }))} images={postImages.map((url) => ({ uri: url }))}
imageIndex={0} imageIndex={0}
visible={isImageModalOpen} visible={isImageModalOpen}
animationType="slide" animationType="slide"
swipeToCloseEnabled swipeToCloseEnabled
onRequestClose={() => setIsImageModalOpen(false)} onRequestClose={() => setIsImageModalOpen(false)}
HeaderComponent={(imageIndex) => _renderImageViewerHeader(imageIndex.imageIndex)} HeaderComponent={(imageIndex) => _renderImageViewerHeader(imageIndex.imageIndex)}
/> />
<OptionsModal <OptionsModal
ref={actionImage} ref={actionImage}
options={[ options={[
intl.formatMessage({ id: 'post.copy_link' }), intl.formatMessage({ id: 'post.copy_link' }),
intl.formatMessage({ id: 'post.gallery_mode' }), intl.formatMessage({ id: 'post.gallery_mode' }),
intl.formatMessage({ id: 'post.save_to_local' }), intl.formatMessage({ id: 'post.save_to_local' }),
intl.formatMessage({ id: 'alert.cancel' }), intl.formatMessage({ id: 'alert.cancel' }),
]} ]}
title={intl.formatMessage({ id: 'post.image' })} title={intl.formatMessage({ id: 'post.image' })}
cancelButtonIndex={3} cancelButtonIndex={3}
onPress={(index) => { onPress={(index) => {
_handleImageOptionPress(index); _handleImageOptionPress(index);
}} }}
/> />
<OptionsModal
ref={actionLink}
options={[
intl.formatMessage({ id: 'post.copy_link' }),
intl.formatMessage({ id: 'alert.external_link' }),
intl.formatMessage({ id: 'alert.cancel' }),
]}
title={intl.formatMessage({ id: 'post.link' })}
cancelButtonIndex={2}
onPress={(index) => {
_handleLinkOptionPress(index);
}}
/>
<OptionsModal <ActionsSheet
ref={actionLink} ref={youtubePlayerRef}
options={[ gestureEnabled={true}
intl.formatMessage({ id: 'post.copy_link' }), hideUnderlay={true}
intl.formatMessage({ id: 'alert.external_link' }), containerStyle={{ backgroundColor: 'black' }}
intl.formatMessage({ id: 'alert.cancel' }), indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}
]} onClose={() => {
title={intl.formatMessage({ id: 'post.link' })} setYoutubeVideoId(null);
cancelButtonIndex={2} setVideoUrl(null);
onPress={(index) => { }}
_handleLinkOptionPress(index); >
}} <VideoPlayer
/> mode={youtubeVideoId ? 'youtube' : 'uri'}
youtubeVideoId={youtubeVideoId}
<ActionsSheet uri={videoUrl}
ref={youtubePlayerRef} startTime={videoStartTime}
gestureEnabled={true} />
hideUnderlay={true} </ActionsSheet>
containerStyle={{ backgroundColor: 'black' }} </Fragment>
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')} );
onClose={() => { },
setYoutubeVideoId(null); );
setVideoUrl(null);
}}
>
<VideoPlayer
mode={youtubeVideoId ? 'youtube' : 'uri'}
youtubeVideoId={youtubeVideoId}
uri={videoUrl}
startTime={videoStartTime}
/>
</ActionsSheet>
</Fragment>
)
})

View File

@ -15,7 +15,7 @@ export default EStyleSheet.create({
marginTop: -4, marginTop: -4,
marginBottom: 4, marginBottom: 4,
}, },
titlePlaceholder:{ titlePlaceholder: {
marginBottom: 4, marginBottom: 4,
}, },
title: { title: {

View File

@ -110,11 +110,7 @@ const PostDisplayView = ({
content, content,
onVotingStart, onVotingStart,
showPayoutDetails = false, showPayoutDetails = false,
postType = isWavePost postType = isWavePost ? PostTypes.WAVE : parentPost ? PostTypes.COMMENT : PostTypes.POST,
? PostTypes.WAVE
: parentPost
? PostTypes.COMMENT
: PostTypes.POST
}: any) => { }: any) => {
if (upvotePopoverRef.current) { if (upvotePopoverRef.current) {
upvotePopoverRef.current.showPopover({ upvotePopoverRef.current.showPopover({
@ -236,7 +232,7 @@ const PostDisplayView = ({
// show quick reply modal // show quick reply modal
const _showQuickReplyModal = (_post = post) => { const _showQuickReplyModal = (_post = post) => {
if (isLoggedIn) { if (isLoggedIn) {
dispatch(showReplyModal({mode:'comment', parentPost:_post})); dispatch(showReplyModal({ mode: 'comment', parentPost: _post }));
} else { } else {
console.log('Not LoggedIn'); console.log('Not LoggedIn');
} }
@ -253,7 +249,6 @@ const PostDisplayView = ({
setIsLoadedComments(true); setIsLoadedComments(true);
}; };
const _postContentView = ( const _postContentView = (
<> <>
{parentPost && <ParentPost post={parentPost} />} {parentPost && <ParentPost post={parentPost} />}
@ -267,12 +262,11 @@ const PostDisplayView = ({
setPostBodyHeight(event.nativeEvent.layout.height); setPostBodyHeight(event.nativeEvent.layout.height);
}} }}
> >
{!!post.title && !post.depth ? (
{ <Text style={styles.title}>{post.title}</Text>
!!post.title && !post.depth ) : (
? <Text style={styles.title}>{post.title}</Text> <View style={styles.titlePlaceholder} />
: <View style={styles.titlePlaceholder} /> )}
}
<PostHeaderDescription <PostHeaderDescription
date={formatedTime} date={formatedTime}
@ -304,7 +298,10 @@ const PostDisplayView = ({
)} )}
{formatedTime} {formatedTime}
</Text> </Text>
<WritePostButton placeholderId={'quick_reply.placeholder'} onPress={_showQuickReplyModal} /> <WritePostButton
placeholderId="quick_reply.placeholder"
onPress={_showQuickReplyModal}
/>
</View> </View>
)} )}
</View> </View>

View File

@ -7,13 +7,7 @@ import React, {
Fragment, Fragment,
useMemo, useMemo,
} from 'react'; } from 'react';
import { import { FlatListProps, FlatList, RefreshControl, ActivityIndicator, View } from 'react-native';
FlatListProps,
FlatList,
RefreshControl,
ActivityIndicator,
View,
} from 'react-native';
import { FlashList } from '@shopify/flash-list'; import { FlashList } from '@shopify/flash-list';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';

View File

@ -1,6 +1,7 @@
import { TextStyle, ViewStyle } from 'react-native'; import { TextStyle, ViewStyle } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
import getWindowDimensions from '../../utils/getWindowDimensions'; import getWindowDimensions from '../../utils/getWindowDimensions';
const { width: SCREEN_WIDTH } = getWindowDimensions(); const { width: SCREEN_WIDTH } = getWindowDimensions();
export default EStyleSheet.create({ export default EStyleSheet.create({

View File

@ -5,6 +5,7 @@ import EStyleSheet from 'react-native-extended-stylesheet';
import QRCodeScanner from 'react-native-qrcode-scanner'; import QRCodeScanner from 'react-native-qrcode-scanner';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { check, request, PERMISSIONS, RESULTS, openSettings } from 'react-native-permissions'; import { check, request, PERMISSIONS, RESULTS, openSettings } from 'react-native-permissions';
import { get } from 'lodash';
import styles from './qrModalStyles'; import styles from './qrModalStyles';
import { useAppDispatch, useAppSelector } from '../../hooks'; import { useAppDispatch, useAppSelector } from '../../hooks';
import { import {
@ -19,13 +20,13 @@ import getWindowDimensions from '../../utils/getWindowDimensions';
import { isHiveUri, getFormattedTx } from '../../utils/hive-uri'; import { isHiveUri, getFormattedTx } from '../../utils/hive-uri';
import { handleHiveUriOperation, resolveTransaction } from '../../providers/hive/dhive'; import { handleHiveUriOperation, resolveTransaction } from '../../providers/hive/dhive';
import bugsnagInstance from '../../config/bugsnag'; import bugsnagInstance from '../../config/bugsnag';
import { get } from 'lodash';
import showLoginAlert from '../../utils/showLoginAlert'; import showLoginAlert from '../../utils/showLoginAlert';
import authType from '../../constants/authType'; import authType from '../../constants/authType';
import { delay } from '../../utils/editor'; import { delay } from '../../utils/editor';
import ROUTES from '../../../src/constants/routeNames'; import ROUTES from '../../constants/routeNames';
const hiveuri = require('hive-uri'); const hiveuri = require('hive-uri');
const screenHeight = getWindowDimensions().height; const screenHeight = getWindowDimensions().height;
interface QRModalProps {} interface QRModalProps {}
@ -149,7 +150,7 @@ export const QRModal = ({}: QRModalProps) => {
await delay(500); // NOTE: it's required to avoid modal mis fire await delay(500); // NOTE: it's required to avoid modal mis fire
dispatch( dispatch(
showWebViewModal({ showWebViewModal({
uri: uri, uri,
}), }),
); );
return; return;
@ -157,10 +158,10 @@ export const QRModal = ({}: QRModalProps) => {
const parsed = hiveuri.decode(uri); const parsed = hiveuri.decode(uri);
const authoritiesMap = new Map(); const authoritiesMap = new Map();
authoritiesMap.set('active', currentAccount?.local?.activeKey ? true : false); authoritiesMap.set('active', !!currentAccount?.local?.activeKey);
authoritiesMap.set('posting', currentAccount?.local?.postingKey ? true : false); authoritiesMap.set('posting', !!currentAccount?.local?.postingKey);
authoritiesMap.set('owner', currentAccount?.local?.ownerKey ? true : false); authoritiesMap.set('owner', !!currentAccount?.local?.ownerKey);
authoritiesMap.set('memo', currentAccount?.local?.memoKey ? true : false); authoritiesMap.set('memo', !!currentAccount?.local?.memoKey);
getFormattedTx(parsed.tx, authoritiesMap) getFormattedTx(parsed.tx, authoritiesMap)
.then(async (formattedTx) => { .then(async (formattedTx) => {
@ -218,7 +219,6 @@ export const QRModal = ({}: QRModalProps) => {
{ key: errObj.authorityKeyType }, { key: errObj.authorityKeyType },
), ),
); );
return;
}); });
}; };

View File

@ -9,25 +9,24 @@ import React, {
useMemo, useMemo,
} from 'react'; } from 'react';
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
import { import { View, Text, TouchableOpacity, Keyboard, Platform, ActivityIndicator } from 'react-native';
View,
Text,
TouchableOpacity,
Keyboard,
Platform,
ActivityIndicator,
} from 'react-native';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { get, debounce } from 'lodash'; import { get, debounce } from 'lodash';
import { postBodySummary } from '@ecency/render-helper'; import { postBodySummary } from '@ecency/render-helper';
import FastImage from 'react-native-fast-image';
import styles from './quickReplyModalStyles'; import styles from './quickReplyModalStyles';
import { Icon, IconButton, MainButton, TextButton, TextInput, UploadsGalleryModal, UserAvatar } from '..';
import { delay } from '../../utils/editor';
import { import {
deleteDraftCacheEntry, Icon,
updateDraftCache, IconButton,
} from '../../redux/actions/cacheActions'; MainButton,
TextButton,
TextInput,
UploadsGalleryModal,
UserAvatar,
} from '..';
import { delay } from '../../utils/editor';
import { deleteDraftCacheEntry, updateDraftCache } from '../../redux/actions/cacheActions';
import { default as ROUTES } from '../../constants/routeNames'; import { default as ROUTES } from '../../constants/routeNames';
import RootNavigation from '../../navigation/rootNavigation'; import RootNavigation from '../../navigation/rootNavigation';
import { Draft } from '../../redux/reducers/cacheReducer'; import { Draft } from '../../redux/reducers/cacheReducer';
@ -35,11 +34,13 @@ import { RootState } from '../../redux/store/store';
import { postQueries } from '../../providers/queries'; import { postQueries } from '../../providers/queries';
import { usePostSubmitter } from './usePostSubmitter'; import { usePostSubmitter } from './usePostSubmitter';
import { MediaInsertData, MediaInsertStatus } from '../uploadsGalleryModal/container/uploadsGalleryModal'; import {
import FastImage from 'react-native-fast-image'; MediaInsertData,
MediaInsertStatus,
} from '../uploadsGalleryModal/container/uploadsGalleryModal';
export interface QuickReplyModalContentProps { export interface QuickReplyModalContentProps {
mode: 'comment' | 'wave' | 'post', mode: 'comment' | 'wave' | 'post';
selectedPost?: any; selectedPost?: any;
handleCloseRef?: any; handleCloseRef?: any;
onClose: () => void; onClose: () => void;
@ -48,17 +49,12 @@ export interface QuickReplyModalContentProps {
const MAX_BODY_LENGTH = 250; const MAX_BODY_LENGTH = 250;
export const QuickReplyModalContent = forwardRef( export const QuickReplyModalContent = forwardRef(
({ ({ mode, selectedPost, onClose }: QuickReplyModalContentProps, ref) => {
mode,
selectedPost,
onClose
}: QuickReplyModalContentProps, ref) => {
const intl = useIntl(); const intl = useIntl();
const dispatch = useDispatch(); const dispatch = useDispatch();
const uploadsGalleryModalRef = useRef(null); const uploadsGalleryModalRef = useRef(null);
const postsCachePrimer = postQueries.usePostsCachePrimer(); const postsCachePrimer = postQueries.usePostsCachePrimer();
const postSubmitter = usePostSubmitter(); const postSubmitter = usePostSubmitter();
@ -76,19 +72,20 @@ export const QuickReplyModalContent = forwardRef(
const parentAuthor = selectedPost ? selectedPost.author : ''; const parentAuthor = selectedPost ? selectedPost.author : '';
const parentPermlink = selectedPost ? selectedPost.permlink : ''; const parentPermlink = selectedPost ? selectedPost.permlink : '';
const headerText =
mode === 'wave'
? intl.formatMessage({ id: 'quick_reply.summary_wave' }, { host: 'ecency.waves' }) // TODO: update based on selected host
: selectedPost && (selectedPost.summary || postBodySummary(selectedPost, 150, Platform.OS));
const headerText = mode === 'wave' const draftId =
? intl.formatMessage({ id: 'quick_reply.summary_wave' }, { host: 'ecency.waves' }) //TODO: update based on selected host mode === 'wave'
: selectedPost && (selectedPost.summary || postBodySummary(selectedPost, 150, Platform.OS)); ? `${currentAccount.name}/ecency.waves` // TODO: update author based on selected host
: `${currentAccount.name}/${parentAuthor}/${parentPermlink}`; // different draftId for each user acount
const draftId = mode === 'wave'
? `${currentAccount.name}/ecency.waves` //TODO: update author based on selected host
: `${currentAccount.name}/${parentAuthor}/${parentPermlink}`; // different draftId for each user acount
const bodyLengthExceeded = useMemo( const bodyLengthExceeded = useMemo(
() => commentValue.length > MAX_BODY_LENGTH && mode === 'wave', () => commentValue.length > MAX_BODY_LENGTH && mode === 'wave',
[commentValue, mode]); [commentValue, mode],
);
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
handleSheetClose() { handleSheetClose() {
@ -112,7 +109,6 @@ export const QuickReplyModalContent = forwardRef(
} }
setCommentValue(_value); setCommentValue(_value);
}, [selectedPost]); }, [selectedPost]);
// add quick comment value into cache // add quick comment value into cache
@ -146,29 +142,24 @@ export const QuickReplyModalContent = forwardRef(
}); });
}; };
// handle submit reply // handle submit reply
const _submitPost = async () => { const _submitPost = async () => {
let _isSuccess = false; let _isSuccess = false;
let _body = mediaUrls.length > 0 ? commentValue + `\n\n ![Wave Media](${mediaUrls[0]})` : commentValue; const _body =
mediaUrls.length > 0 ? `${commentValue}\n\n ![Wave Media](${mediaUrls[0]})` : commentValue;
switch (mode) { switch (mode) {
case 'comment': case 'comment':
_isSuccess = await postSubmitter.submitReply(_body, selectedPost); _isSuccess = await postSubmitter.submitReply(_body, selectedPost);
break;; break;
case 'wave': case 'wave':
_isSuccess = await postSubmitter.submitWave(_body); _isSuccess = await postSubmitter.submitWave(_body);
break; break;
default: default:
throw new Error("mode needs implementing") throw new Error('mode needs implementing');
} }
if (_isSuccess) { if (_isSuccess) {
// delete quick comment draft cache if it exist // delete quick comment draft cache if it exist
if (draftsCollection && draftsCollection[draftId]) { if (draftsCollection && draftsCollection[draftId]) {
dispatch(deleteDraftCacheEntry(draftId)); dispatch(deleteDraftCacheEntry(draftId));
@ -178,13 +169,10 @@ export const QuickReplyModalContent = forwardRef(
} else { } else {
_addQuickCommentIntoCache(); // add comment value into cache if there is error while posting comment _addQuickCommentIntoCache(); // add comment value into cache if there is error while posting comment
} }
}; };
const _handleMediaInsert = (data: MediaInsertData[]) => { const _handleMediaInsert = (data: MediaInsertData[]) => {
const _insertUrls: string[] = [] const _insertUrls: string[] = [];
const _item = data[0]; const _item = data[0];
@ -192,7 +180,7 @@ export const QuickReplyModalContent = forwardRef(
switch (_item.status) { switch (_item.status) {
case MediaInsertStatus.READY: case MediaInsertStatus.READY:
if (_item.url) { if (_item.url) {
_insertUrls.push(_item.url) _insertUrls.push(_item.url);
} }
break; break;
case MediaInsertStatus.FAILED: case MediaInsertStatus.FAILED:
@ -201,14 +189,10 @@ export const QuickReplyModalContent = forwardRef(
} }
} }
setMediaModalVisible(false); setMediaModalVisible(false);
uploadsGalleryModalRef.current?.toggleModal(false); uploadsGalleryModalRef.current?.toggleModal(false);
setMediaUrls(_insertUrls); setMediaUrls(_insertUrls);
};
}
const _handleExpandBtn = async () => { const _handleExpandBtn = async () => {
if (selectedPost) { if (selectedPost) {
@ -228,10 +212,10 @@ export const QuickReplyModalContent = forwardRef(
const _handleMediaBtn = () => { const _handleMediaBtn = () => {
if (uploadsGalleryModalRef.current) { if (uploadsGalleryModalRef.current) {
uploadsGalleryModalRef.current.toggleModal(!mediaModalVisible) uploadsGalleryModalRef.current.toggleModal(!mediaModalVisible);
setMediaModalVisible(!mediaModalVisible) setMediaModalVisible(!mediaModalVisible);
} }
} };
const _deboucedCacheUpdate = useCallback(debounce(_addQuickCommentIntoCache, 500), []); const _deboucedCacheUpdate = useCallback(debounce(_addQuickCommentIntoCache, 500), []);
@ -240,9 +224,6 @@ export const QuickReplyModalContent = forwardRef(
_deboucedCacheUpdate(value); _deboucedCacheUpdate(value);
}; };
// VIEW_RENDERERS // VIEW_RENDERERS
const _renderSummary = () => ( const _renderSummary = () => (
@ -253,8 +234,6 @@ export const QuickReplyModalContent = forwardRef(
</TouchableOpacity> </TouchableOpacity>
); );
const _renderAvatar = () => ( const _renderAvatar = () => (
<View style={styles.avatarAndNameContainer}> <View style={styles.avatarAndNameContainer}>
<UserAvatar noAction username={currentAccount.username} /> <UserAvatar noAction username={currentAccount.username} />
@ -264,14 +243,12 @@ export const QuickReplyModalContent = forwardRef(
</View> </View>
); );
const _renderMediaPanel = () => { const _renderMediaPanel = () => {
const _onPress = () => { const _onPress = () => {
setMediaUrls([]) setMediaUrls([]);
} };
const _minusIcon = ( const _minusIcon = !isUploading && (
!isUploading &&
<View style={styles.minusContainer}> <View style={styles.minusContainer}>
<Icon <Icon
color={EStyleSheet.value('$pureWhite')} color={EStyleSheet.value('$pureWhite')}
@ -280,52 +257,46 @@ export const QuickReplyModalContent = forwardRef(
size={16} size={16}
/> />
</View> </View>
) );
const _mediaThumb = !mediaModalVisible && mediaUrls.length > 0 && (
<TouchableOpacity onPress={_onPress} disabled={isUploading}>
<FastImage source={{ uri: mediaUrls[0] }} style={styles.mediaItem} />
{_minusIcon}
</TouchableOpacity>
);
const _mediaThumb = ( const _uploadingPlaceholder = isUploading && (
!mediaModalVisible && mediaUrls.length > 0 && ( <View style={styles.mediaItem}>
<TouchableOpacity onPress={_onPress} disabled={isUploading}>
<FastImage
source={{ uri: mediaUrls[0] }}
style={styles.mediaItem}
/>
{_minusIcon}
</TouchableOpacity>
)
)
const _uploadingPlaceholder = (
isUploading && <View style={styles.mediaItem}>
<ActivityIndicator /> <ActivityIndicator />
</View> </View>
) );
return <Fragment> return (
{_mediaThumb} <Fragment>
{_uploadingPlaceholder} {_mediaThumb}
{_uploadingPlaceholder}
<UploadsGalleryModal
ref={uploadsGalleryModalRef}
isPreviewActive={false}
username={currentAccount.username}
allowMultiple={false}
hideToolbarExtension={() => {
setMediaModalVisible(false);
}}
handleMediaInsert={_handleMediaInsert}
setIsUploading={setIsUploading}
/>
</Fragment>
}
<UploadsGalleryModal
ref={uploadsGalleryModalRef}
isPreviewActive={false}
username={currentAccount.username}
allowMultiple={false}
hideToolbarExtension={() => {
setMediaModalVisible(false);
}}
handleMediaInsert={_handleMediaInsert}
setIsUploading={setIsUploading}
/>
</Fragment>
);
};
const _renderExpandBtn = () => { const _renderExpandBtn = () => {
const _lengthTextStyle = { const _lengthTextStyle = {
...styles.toolbarSpacer, ...styles.toolbarSpacer,
color: EStyleSheet.value(bodyLengthExceeded ? '$primaryRed' : '$iconColor') color: EStyleSheet.value(bodyLengthExceeded ? '$primaryRed' : '$iconColor'),
} };
return ( return (
<View style={styles.toolbarContainer}> <View style={styles.toolbarContainer}>
@ -346,16 +317,11 @@ export const QuickReplyModalContent = forwardRef(
color={EStyleSheet.value('$primaryBlack')} color={EStyleSheet.value('$primaryBlack')}
/> />
) : ( ) : (
<Text style={_lengthTextStyle}> <Text style={_lengthTextStyle}>{`${commentValue.length}/${MAX_BODY_LENGTH}`}</Text>
{`${commentValue.length}/${MAX_BODY_LENGTH}`}
</Text>
)} )}
</View> </View>
); );
} };
const _renderReplyBtn = () => { const _renderReplyBtn = () => {
const _titleId = mode !== 'comment' ? 'quick_reply.publish' : 'quick_reply.reply'; const _titleId = mode !== 'comment' ? 'quick_reply.publish' : 'quick_reply.reply';
@ -378,13 +344,11 @@ export const QuickReplyModalContent = forwardRef(
isLoading={postSubmitter.isSending} isLoading={postSubmitter.isSending}
/> />
</View> </View>
) );
}; };
const _placeholderId =
mode === 'comment' ? 'quick_reply.placeholder' : 'quick_reply.placeholder_wave';
const _placeholderId = mode === 'comment' ? 'quick_reply.placeholder' : 'quick_reply.placeholder_wave'
return ( return (
<View style={styles.modalContainer}> <View style={styles.modalContainer}>
@ -409,14 +373,11 @@ export const QuickReplyModalContent = forwardRef(
{_renderMediaPanel()} {_renderMediaPanel()}
<View style={styles.footer}> <View style={styles.footer}>
{_renderExpandBtn()} {_renderExpandBtn()}
{_renderReplyBtn()} {_renderReplyBtn()}
</View> </View>
</View> </View>
) );
}, },
); );

View File

@ -108,8 +108,8 @@ export default EStyleSheet.create({
width: 96, width: 96,
borderRadius: 16, borderRadius: 16,
backgroundColor: '$primaryLightBackground', backgroundColor: '$primaryLightBackground',
justifyContent:'center', justifyContent: 'center',
alignItems:'center' alignItems: 'center',
} as ImageStyle, } as ImageStyle,
minusContainer: { minusContainer: {
position: 'absolute', position: 'absolute',
@ -119,12 +119,11 @@ export default EStyleSheet.create({
borderRadius: 16, borderRadius: 16,
padding: 2, padding: 2,
} as ViewStyle, } as ViewStyle,
toolbarContainer:{ toolbarContainer: {
flexDirection:'row', flexDirection: 'row',
alignItems:'center' alignItems: 'center',
} as ViewStyle, } as ViewStyle,
toolbarSpacer:{ toolbarSpacer: {
marginLeft:8 marginLeft: 8,
} as ViewStyle, } as ViewStyle,
}); });

View File

@ -9,7 +9,7 @@ const QuickReplyModal = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const replyModalVisible = useAppSelector((state) => state.ui.replyModalVisible); const replyModalVisible = useAppSelector((state) => state.ui.replyModalVisible);
const replyModalData:PostEditorModalData = useAppSelector((state) => state.ui.replyModalData); const replyModalData: PostEditorModalData = useAppSelector((state) => state.ui.replyModalData);
const modalContentRef = useRef(null); const modalContentRef = useRef(null);
const _onClose = () => { const _onClose = () => {

View File

@ -1,172 +1,155 @@
import { useDispatch } from "react-redux"; import { useDispatch } from 'react-redux';
import { useAppSelector } from "../../hooks"; import { Alert } from 'react-native';
import { postComment } from "../../providers/hive/dhive"; import { useIntl } from 'react-intl';
import { extractMetadata, generateUniquePermlink, makeJsonMetadata } from "../../utils/editor"; import { useState } from 'react';
import { Alert } from "react-native"; import { useAppSelector } from '../../hooks';
import { updateCommentCache } from "../../redux/actions/cacheActions"; import { postComment } from '../../providers/hive/dhive';
import { toastNotification } from "../../redux/actions/uiAction"; import { extractMetadata, generateUniquePermlink, makeJsonMetadata } from '../../utils/editor';
import { useIntl } from "react-intl"; import { updateCommentCache } from '../../redux/actions/cacheActions';
import { useState } from "react"; import { toastNotification } from '../../redux/actions/uiAction';
import { useUserActivityMutation, wavesQueries } from "../../providers/queries"; import { useUserActivityMutation, wavesQueries } from '../../providers/queries';
import { PointActivityIds } from "../../providers/ecency/ecency.types"; import { PointActivityIds } from '../../providers/ecency/ecency.types';
import { usePublishWaveMutation } from "../../providers/queries/postQueries/wavesQueries"; import { usePublishWaveMutation } from '../../providers/queries/postQueries/wavesQueries';
import { PostTypes } from "../../constants/postTypes"; import { PostTypes } from '../../constants/postTypes';
export const usePostSubmitter = () => { export const usePostSubmitter = () => {
const dispatch = useDispatch();
const intl = useIntl();
const dispatch = useDispatch(); const pusblishWaveMutation = usePublishWaveMutation();
const intl = useIntl();
const pusblishWaveMutation = usePublishWaveMutation(); const currentAccount = useAppSelector((state) => state.account.currentAccount);
const pinCode = useAppSelector((state) => state.application.pin);
const userActivityMutation = useUserActivityMutation();
const [isSending, setIsSending] = useState(false);
// handle submit reply
const _submitReply = async (
commentBody: string,
parentPost: any,
postType: PostTypes = PostTypes.COMMENT,
) => {
if (!commentBody) {
return false;
}
if (isSending) {
return false;
}
const currentAccount = useAppSelector((state) => state.account.currentAccount); if (currentAccount) {
const pinCode = useAppSelector(state => state.application.pin); setIsSending(true);
const userActivityMutation = useUserActivityMutation();
const [isSending, setIsSending] = useState(false);
const _prefix =
postType === PostTypes.WAVE ? postType : `re-${parentPost.author.replace(/\./g, '')}`;
const permlink = generateUniquePermlink(_prefix);
// handle submit reply const author = currentAccount.name;
const _submitReply = async (commentBody: string, parentPost: any, postType: PostTypes = PostTypes.COMMENT) => { const parentAuthor = parentPost.author;
if (!commentBody) { const parentPermlink = parentPost.permlink;
return false; const parentTags = parentPost.json_metadata.tags;
} const category = parentPost.category || '';
if (isSending) { const url = `/${category}/@${parentAuthor}/${parentPermlink}#@${author}/${permlink}`;
return false;
}
if (currentAccount) { // adding jsonmeta with image ratios here....
setIsSending(true); const meta = await extractMetadata({
body: commentBody,
fetchRatios: true,
postType,
});
const jsonMetadata = makeJsonMetadata(meta, parentTags || ['ecency']);
const _prefix = postType === PostTypes.WAVE console.log(
? postType currentAccount,
: `re-${parentPost.author.replace(/\./g, '')}` pinCode,
const permlink = generateUniquePermlink(_prefix); parentAuthor,
parentPermlink,
permlink,
commentBody,
jsonMetadata,
);
const author = currentAccount.name; try {
const parentAuthor = parentPost.author; const response = await postComment(
const parentPermlink = parentPost.permlink; currentAccount,
const parentTags = parentPost.json_metadata.tags; pinCode,
const category = parentPost.category || ''; parentAuthor,
const url = `/${category}/@${parentAuthor}/${parentPermlink}#@${author}/${permlink}`; parentPermlink,
permlink,
commentBody,
jsonMetadata,
);
//adding jsonmeta with image ratios here.... userActivityMutation.mutate({
const meta = await extractMetadata({ pointsTy: PointActivityIds.COMMENT,
body: commentBody, transactionId: response.id,
fetchRatios: true, });
postType setIsSending(false);
})
const jsonMetadata = makeJsonMetadata(meta, parentTags || ['ecency'])
console.log( dispatch(
currentAccount, toastNotification(
pinCode, intl.formatMessage({
parentAuthor, id: 'alert.success',
parentPermlink, }),
permlink, ),
commentBody, );
jsonMetadata
);
// add comment cache entry
const _cacheCommentData = {
author,
permlink,
url,
parent_author: parentAuthor,
parent_permlink: parentPermlink,
markdownBody: commentBody,
json_metadata: jsonMetadata,
};
try { dispatch(
const response = await postComment( updateCommentCache(`${author}/${permlink}`, _cacheCommentData, {
currentAccount, parentTags: parentTags || ['ecency'],
pinCode, }),
parentAuthor, );
parentPermlink,
permlink,
commentBody,
jsonMetadata
)
userActivityMutation.mutate({ return _cacheCommentData;
pointsTy: PointActivityIds.COMMENT, } catch (error) {
transactionId: response.id, console.log(error);
}); Alert.alert(
setIsSending(false); intl.formatMessage({
id: 'alert.something_wrong',
dispatch( }),
toastNotification( error.message || JSON.stringify(error),
intl.formatMessage({ );
id: 'alert.success',
}),
),
);
// add comment cache entry
const _cacheCommentData = {
author,
permlink,
url,
parent_author: parentAuthor,
parent_permlink: parentPermlink,
markdownBody: commentBody,
json_metadata: jsonMetadata
}
dispatch(
updateCommentCache(
`${author}/${permlink}`,
_cacheCommentData,
{
parentTags: parentTags || ['ecency'],
},
),
);
return _cacheCommentData;
} catch (error) {
console.log(error);
Alert.alert(
intl.formatMessage({
id: 'alert.something_wrong',
}),
error.message || JSON.stringify(error),
);
setIsSending(false);
return false;
}
}
setIsSending(false);
return false; return false;
}; }
//feteced lates wafves container and post wave to that container
const _submitWave = async (body: string) => {
try {
const _wavesHost = 'ecency.waves' //TODO: make waves host selection dynamic
const latestWavesPost = await wavesQueries.fetchLatestWavesContainer(_wavesHost);
const _cacheCommentData = await _submitReply(body, latestWavesPost, PostTypes.WAVE)
if (_cacheCommentData) {
pusblishWaveMutation.mutate(_cacheCommentData)
}
return _cacheCommentData
} catch (err) {
Alert.alert("Fail", err.message)
return false;
}
} }
return false;
};
// feteced lates wafves container and post wave to that container
const _submitWave = async (body: string) => {
try {
const _wavesHost = 'ecency.waves'; // TODO: make waves host selection dynamic
const latestWavesPost = await wavesQueries.fetchLatestWavesContainer(_wavesHost);
return { const _cacheCommentData = await _submitReply(body, latestWavesPost, PostTypes.WAVE);
submitReply: _submitReply,
submitWave: _submitWave, if (_cacheCommentData) {
isSending pusblishWaveMutation.mutate(_cacheCommentData);
}
return _cacheCommentData;
} catch (err) {
Alert.alert('Fail', err.message);
return false;
} }
};
} return {
submitReply: _submitReply,
submitWave: _submitWave,
isSending,
};
};

View File

@ -2,12 +2,12 @@ import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
// Actions // Actions
import { useDrawerStatus } from '@react-navigation/drawer';
import { logout, toggleAccountsBottomSheet } from '../../../redux/actions/uiAction'; import { logout, toggleAccountsBottomSheet } from '../../../redux/actions/uiAction';
import { setInitPosts, setFeedPosts } from '../../../redux/actions/postsAction'; import { setInitPosts, setFeedPosts } from '../../../redux/actions/postsAction';
// Component // Component
import SideMenuView from '../view/sideMenuView'; import SideMenuView from '../view/sideMenuView';
import { useDrawerStatus } from '@react-navigation/drawer';
import { updateCurrentAccount } from '../../../redux/actions/accountAction'; import { updateCurrentAccount } from '../../../redux/actions/accountAction';
import { getUser } from '../../../providers/hive/dhive'; import { getUser } from '../../../providers/hive/dhive';
import bugsnapInstance from '../../../config/bugsnag'; import bugsnapInstance from '../../../config/bugsnag';
@ -16,40 +16,33 @@ const SideMenuContainer = ({ navigation }) => {
const dispatch = useDispatch(); const dispatch = useDispatch();
const drawerStatus = useDrawerStatus(); const drawerStatus = useDrawerStatus();
const isLoggedIn = useSelector((state) => state.application.isLoggedIn); const isLoggedIn = useSelector((state) => state.application.isLoggedIn);
const currentAccount = useSelector((state) => state.account.currentAccount); const currentAccount = useSelector((state) => state.account.currentAccount);
const isVisibleAccountsBottomSheet = useSelector( const isVisibleAccountsBottomSheet = useSelector(
(state) => state.ui.isVisibleAccountsBottomSheet, (state) => state.ui.isVisibleAccountsBottomSheet,
); );
useEffect(() => {
useEffect(()=>{ if (drawerStatus === 'open') {
if(drawerStatus === 'open'){ // update profile on drawer open
//update profile on drawer open
_updateUserData(); _updateUserData();
} }
}, [drawerStatus]);
}, [drawerStatus])
// fetches and update user data
//fetches and update user data
const _updateUserData = async () => { const _updateUserData = async () => {
try{ try {
if(currentAccount?.username){ if (currentAccount?.username) {
let accountData = await getUser(currentAccount.username); const accountData = await getUser(currentAccount.username);
if(accountData){ if (accountData) {
dispatch(updateCurrentAccount({...currentAccount, ...accountData})) dispatch(updateCurrentAccount({ ...currentAccount, ...accountData }));
} }
} }
} catch (err) {
} catch(err){ console.warn('failed to update user data');
console.warn("failed to update user data")
bugsnapInstance.notify(err); bugsnapInstance.notify(err);
} }
};
}
const _navigateToRoute = (route = null) => { const _navigateToRoute = (route = null) => {
if (route) { if (route) {

View File

@ -2,63 +2,61 @@ import { TextStyle, StyleSheet, ViewStyle } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({ export default EStyleSheet.create({
modalStyle: { modalStyle: {
flex: 1, flex: 1,
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
margin:0, margin: 0,
paddingTop:32, paddingTop: 32,
paddingBottom:8 paddingBottom: 8,
}, },
container:{ container: {
flexGrow:1, flexGrow: 1,
marginTop:24, marginTop: 24,
paddingHorizontal:24, paddingHorizontal: 24,
}, },
inputContainer:{ inputContainer: {
flex:1 flex: 1,
} as ViewStyle, } as ViewStyle,
titleInput:{ titleInput: {
color: '$primaryBlack', color: '$primaryBlack',
fontWeight: 'bold', fontWeight: 'bold',
fontSize: 18, fontSize: 18,
textAlignVertical: 'top', textAlignVertical: 'top',
paddingVertical: 0, paddingVertical: 0,
backgroundColor:'$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
borderBottomWidth:StyleSheet.hairlineWidth, borderBottomWidth: StyleSheet.hairlineWidth,
borderBottomColor:'$primaryDarkGray' borderBottomColor: '$primaryDarkGray',
} as TextStyle, } as TextStyle,
bodyWrapper: { bodyWrapper: {
fontSize: 16, fontSize: 16,
paddingTop: 16, paddingTop: 16,
paddingBottom: 0, // On android side, textinput has default padding paddingBottom: 0, // On android side, textinput has default padding
color: '$primaryBlack', color: '$primaryBlack',
textAlignVertical: 'top', textAlignVertical: 'top',
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
}, },
btnText:{ btnText: {
color:'$pureWhite' color: '$pureWhite',
} as TextStyle, } as TextStyle,
saveButton:{ saveButton: {
backgroundColor: '$primaryBlue',
backgroundColor:'$primaryBlue', width: 150,
width:150, paddingVertical: 16,
paddingVertical:16, borderRadius: 32,
borderRadius:32, justifyContent: 'center',
justifyContent:'center', alignItems: 'center',
alignItems:'center' } as ViewStyle,
} as ViewStyle, closeButton: {
closeButton:{ marginRight: 16,
marginRight:16, paddingVertical: 8,
paddingVertical:8, borderRadius: 16,
borderRadius:16, justifyContent: 'center',
justifyContent:'center', alignItems: 'center',
alignItems:'center' } as ViewStyle,
} as ViewStyle, actionPanel: {
actionPanel:{ flexDirection: 'row',
flexDirection:'row', justifyContent: 'flex-end',
justifyContent:'flex-end', alignItems: 'center',
alignItems:'center', marginBottom: 16,
marginBottom:16 } as ViewStyle,
} as ViewStyle, });
})

View File

@ -9,44 +9,43 @@ export default EStyleSheet.create({
}, },
bodyWrapper: { bodyWrapper: {
flex: 3, flex: 3,
paddingHorizontal:16 paddingHorizontal: 16,
}, },
floatingContainer:{ floatingContainer: {
position:'absolute', position: 'absolute',
bottom:0, bottom: 0,
right:20, right: 20,
justifyContent:'flex-end', justifyContent: 'flex-end',
zIndex:10 zIndex: 10,
} as ViewStyle, } as ViewStyle,
itemWrapper: { itemWrapper: {
paddingHorizontal: 16, paddingHorizontal: 16,
paddingVertical:8, paddingVertical: 8,
borderRadius: 8, borderRadius: 8,
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
}, },
itemHeader:{ itemHeader: {
flexDirection:'row', flexDirection: 'row',
alignItems:'center', alignItems: 'center',
height:35 height: 35,
}, },
itemWrapperGray: { itemWrapperGray: {
backgroundColor: '$primaryLightBackground', backgroundColor: '$primaryLightBackground',
}, },
itemIcon:{ itemIcon: {
color:'$primaryDarkGray', color: '$primaryDarkGray',
}, },
itemIconWrapper:{ itemIconWrapper: {
marginLeft:8, marginLeft: 8,
}, },
title: { title: {
fontWeight: '700', fontWeight: '700',
flex:1, flex: 1,
fontSize:16, fontSize: 16,
color:'$primaryBlack' color: '$primaryBlack',
}, },
body: { body: {
paddingBottom:8, paddingBottom: 8,
color:'$primaryBlack' color: '$primaryBlack',
}, },
}); });

View File

@ -4,7 +4,6 @@ import { TabbedPostsProps } from '../services/tabbedPostsModels';
import { StackedTabBar, TabItem } from '../view/stackedTabBar'; import { StackedTabBar, TabItem } from '../view/stackedTabBar';
import TabContent from '../view/tabContent'; import TabContent from '../view/tabContent';
export const TabbedPosts = ({ export const TabbedPosts = ({
filterOptions, filterOptions,
filterOptionsValue, filterOptionsValue,
@ -20,45 +19,48 @@ export const TabbedPosts = ({
onTabChange, onTabChange,
...props ...props
}: TabbedPostsProps) => { }: TabbedPostsProps) => {
// initialize state
const [initialTabIndex] = useState(
selectedOptionIndex == 0 && stackedTabs ? filterOptions.length : selectedOptionIndex,
);
//initialize state const mainFilters = filterOptions.map(
const [initialTabIndex] = useState(selectedOptionIndex == 0 && stackedTabs ? filterOptions.length : selectedOptionIndex) (label, index) =>
({
const mainFilters = filterOptions.map((label, index) => ({ filterKey: filterOptionsValue[index],
filterKey: filterOptionsValue[index], label,
label } as TabItem),
} as TabItem)); );
const subFilters = feedSubfilterOptions const subFilters = feedSubfilterOptions
? feedSubfilterOptions.map((label, index) => ({ ? feedSubfilterOptions.map(
filterKey: feedSubfilterOptionsValue[index], (label, index) =>
label ({
} as TabItem)) filterKey: feedSubfilterOptionsValue[index],
label,
} as TabItem),
)
: []; : [];
const combinedFilters = [...mainFilters, ...subFilters] const combinedFilters = [...mainFilters, ...subFilters];
const [selectedFilter, setSelectedFilter] = useState(combinedFilters[initialTabIndex].filterKey) const [selectedFilter, setSelectedFilter] = useState(combinedFilters[initialTabIndex].filterKey);
const [filterScrollRequest, createFilterScrollRequest] = useState<string | null>(null) const [filterScrollRequest, createFilterScrollRequest] = useState<string | null>(null);
// components actions
//components actions
const _onFilterSelect = (filter: string) => { const _onFilterSelect = (filter: string) => {
if (filter === selectedFilter) { if (filter === selectedFilter) {
createFilterScrollRequest(selectedFilter) createFilterScrollRequest(selectedFilter);
} else { } else {
setSelectedFilter(filter) setSelectedFilter(filter);
} }
} };
const _onScrollRequestProcessed = () => { const _onScrollRequestProcessed = () => {
createFilterScrollRequest(null); createFilterScrollRequest(null);
} };
// initialize first set of pages
//initialize first set of pages
const pages = combinedFilters.map((filter, index) => { const pages = combinedFilters.map((filter, index) => {
if (tabContentOverrides && tabContentOverrides.has(index)) { if (tabContentOverrides && tabContentOverrides.has(index)) {
return tabContentOverrides.get(index); return tabContentOverrides.get(index);
@ -76,11 +78,10 @@ export const TabbedPosts = ({
onScrollRequestProcessed={_onScrollRequestProcessed} onScrollRequestProcessed={_onScrollRequestProcessed}
{...props} {...props}
/> />
) );
}); });
// render tab bar
//render tab bar
const _renderTabBar = (props) => { const _renderTabBar = (props) => {
return ( return (
<StackedTabBar <StackedTabBar
@ -92,9 +93,8 @@ export const TabbedPosts = ({
toggleHideImagesFlag={imagesToggleEnabled} toggleHideImagesFlag={imagesToggleEnabled}
pageType={pageType} pageType={pageType}
/> />
) );
} };
return ( return (
<ScrollableTabView <ScrollableTabView
@ -107,5 +107,4 @@ export const TabbedPosts = ({
{pages} {pages}
</ScrollableTabView> </ScrollableTabView>
); );
};
}

View File

@ -184,12 +184,11 @@ export const loadPosts = async ({
} }
}; };
export const fetchPromotedEntries = async (username: string, nsfwFilter:string) => { export const fetchPromotedEntries = async (username: string, nsfwFilter: string) => {
try { try {
const posts = await getPromotedEntries(username); const posts = await getPromotedEntries(username);
return Array.isArray(posts) ? filterNsfwPost(posts, nsfwFilter) : []; return Array.isArray(posts) ? filterNsfwPost(posts, nsfwFilter) : [];
} catch (err) { } catch (err) {
console.warn('Failed to get promoted posts, ', err); console.warn('Failed to get promoted posts, ', err);
} }

View File

@ -1,6 +1,11 @@
import React, { useState, useEffect, useRef } from 'react'; import React, { useState, useEffect, useRef } from 'react';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { AppState, NativeEventSubscription, NativeScrollEvent, NativeSyntheticEvent } from 'react-native'; import {
AppState,
NativeEventSubscription,
NativeScrollEvent,
NativeSyntheticEvent,
} from 'react-native';
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import BackgroundTimer from 'react-native-background-timer'; import BackgroundTimer from 'react-native-background-timer';
import PostsList from '../../postsList'; import PostsList from '../../postsList';
@ -41,7 +46,7 @@ const TabContent = ({
}: TabContentProps) => { }: TabContentProps) => {
let _isMounted = true; let _isMounted = true;
//redux properties // redux properties
const dispatch = useDispatch(); const dispatch = useDispatch();
const isLoggedIn = useSelector((state) => state.application.isLoggedIn); const isLoggedIn = useSelector((state) => state.application.isLoggedIn);
const nsfw = useSelector((state) => state.application.nsfw); const nsfw = useSelector((state) => state.application.nsfw);
@ -49,11 +54,10 @@ const TabContent = ({
const currentAccount = useSelector((state) => state.account.currentAccount); const currentAccount = useSelector((state) => state.account.currentAccount);
const initPosts = useSelector((state) => state.posts.initPosts); const initPosts = useSelector((state) => state.posts.initPosts);
const { username } = currentAccount;
const username = currentAccount.username;
const userPinned = currentAccount.about?.profile?.pinned; const userPinned = currentAccount.about?.profile?.pinned;
//state // state
const [posts, setPosts] = useState([]); const [posts, setPosts] = useState([]);
const [promotedPosts, setPromotedPosts] = useState([]); const [promotedPosts, setPromotedPosts] = useState([]);
const [sessionUser, setSessionUser] = useState(username); const [sessionUser, setSessionUser] = useState(username);
@ -62,21 +66,20 @@ const TabContent = ({
const [enableScrollTop, setEnableScrollTop] = useState(false); const [enableScrollTop, setEnableScrollTop] = useState(false);
const [curPinned, setCurPinned] = useState(pinnedPermlink); const [curPinned, setCurPinned] = useState(pinnedPermlink);
//refs // refs
let postsListRef = useRef<PostsListRef>(); const postsListRef = useRef<PostsListRef>();
const appState = useRef(AppState.currentState); const appState = useRef(AppState.currentState);
const appStateSubRef = useRef<NativeEventSubscription|null>() const appStateSubRef = useRef<NativeEventSubscription | null>();
const postsRef = useRef(posts); const postsRef = useRef(posts);
const sessionUserRef = useRef(sessionUser); const sessionUserRef = useRef(sessionUser);
const postFetchTimerRef = useRef<any>(null); const postFetchTimerRef = useRef<any>(null);
//init state refs; // init state refs;
postsRef.current = posts; postsRef.current = posts;
sessionUserRef.current = sessionUser; sessionUserRef.current = sessionUser;
//side effects // side effects
useEffect(() => { useEffect(() => {
if (isFeedScreen) { if (isFeedScreen) {
appStateSubRef.current = AppState.addEventListener('change', _handleAppStateChange); appStateSubRef.current = AppState.addEventListener('change', _handleAppStateChange);
} }
@ -88,7 +91,7 @@ const TabContent = ({
useEffect(() => { useEffect(() => {
if (isConnected && (username !== sessionUser || forceLoadPosts)) { if (isConnected && (username !== sessionUser || forceLoadPosts)) {
_initContent(false, username); _initContent(false, username);
} }
}, [username, forceLoadPosts]); }, [username, forceLoadPosts]);
@ -113,7 +116,7 @@ const TabContent = ({
const _cleanup = () => { const _cleanup = () => {
_isMounted = false; _isMounted = false;
if (postFetchTimerRef.current) { if (postFetchTimerRef.current) {
BackgroundTimer.clearTimeout(postFetchTimerRef.current) BackgroundTimer.clearTimeout(postFetchTimerRef.current);
postFetchTimerRef.current = null; postFetchTimerRef.current = null;
} }
if (isFeedScreen && appStateSubRef.current) { if (isFeedScreen && appStateSubRef.current) {
@ -121,7 +124,7 @@ const TabContent = ({
} }
}; };
//actions // actions
const _handleAppStateChange = (nextAppState) => { const _handleAppStateChange = (nextAppState) => {
if ( if (
appState.current.match(/inactive|background/) && appState.current.match(/inactive|background/) &&
@ -166,7 +169,7 @@ const TabContent = ({
} }
}; };
//fetch posts from server // fetch posts from server
const _loadPosts = async ({ const _loadPosts = async ({
shouldReset = false, shouldReset = false,
isLatestPostsCheck = false, isLatestPostsCheck = false,
@ -225,7 +228,7 @@ const TabContent = ({
} }
}; };
//schedules post fetch // schedules post fetch
const _scheduleLatestPostsCheck = (firstPost: any) => { const _scheduleLatestPostsCheck = (firstPost: any) => {
if (firstPost) { if (firstPost) {
if (postFetchTimerRef.current) { if (postFetchTimerRef.current) {
@ -241,13 +244,12 @@ const TabContent = ({
isLatestPostsCheck, isLatestPostsCheck,
}); });
}, timeLeft); }, timeLeft);
} }
}; };
//processes response from loadPost // processes response from loadPost
const _postProcessLoadResult = ({ updatedPosts, latestPosts }: any) => { const _postProcessLoadResult = ({ updatedPosts, latestPosts }: any) => {
//process new posts avatart // process new posts avatart
if (latestPosts && Array.isArray(latestPosts)) { if (latestPosts && Array.isArray(latestPosts)) {
if (latestPosts.length > 0) { if (latestPosts.length > 0) {
setLatestPosts(latestPosts); setLatestPosts(latestPosts);
@ -256,14 +258,14 @@ const TabContent = ({
} }
} }
//process returned data // process returned data
if (Array.isArray(updatedPosts)) { if (Array.isArray(updatedPosts)) {
if (updatedPosts.length) { if (updatedPosts.length) {
//match new and old first post // match new and old first post
const firstPostChanged = const firstPostChanged =
posts.length == 0 || posts[0].permlink !== updatedPosts[0].permlink; posts.length == 0 || posts[0].permlink !== updatedPosts[0].permlink;
if (isFeedScreen && firstPostChanged) { if (isFeedScreen && firstPostChanged) {
//schedule refetch of new posts by checking time of current post // schedule refetch of new posts by checking time of current post
_scheduleLatestPostsCheck(updatedPosts[0]); _scheduleLatestPostsCheck(updatedPosts[0]);
if (isInitialTab) { if (isInitialTab) {
@ -271,14 +273,14 @@ const TabContent = ({
} }
} }
} else if (isFeedScreen && isInitialTab) { } else if (isFeedScreen && isInitialTab) {
//clear posts cache if no first tab posts available, precautionary measure for accoutn change // clear posts cache if no first tab posts available, precautionary measure for accoutn change
dispatch(setInitPosts([])); dispatch(setInitPosts([]));
} }
setPosts(updatedPosts); setPosts(updatedPosts);
} }
}; };
//view related routines // view related routines
const _onPostsPopupPress = () => { const _onPostsPopupPress = () => {
_scrollToTop(); _scrollToTop();
_getPromotedPosts(); _getPromotedPosts();
@ -303,7 +305,7 @@ const TabContent = ({
} }
}; };
//view rendereres // view rendereres
const _renderEmptyContent = () => { const _renderEmptyContent = () => {
return <TabEmptyView filterKey={filterKey} isNoPost={tabMeta.isNoPost} />; return <TabEmptyView filterKey={filterKey} isNoPost={tabMeta.isNoPost} />;
}; };
@ -317,8 +319,8 @@ const TabContent = ({
); );
const _onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => { const _onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
let currentOffset = event.nativeEvent.contentOffset.y; const currentOffset = event.nativeEvent.contentOffset.y;
let scrollUp = currentOffset < scrollOffset; const scrollUp = currentOffset < scrollOffset;
scrollOffset = currentOffset; scrollOffset = currentOffset;
if (scrollUp && !blockPopup && currentOffset > SCROLL_POPUP_THRESHOLD) { if (scrollUp && !blockPopup && currentOffset > SCROLL_POPUP_THRESHOLD) {
@ -329,9 +331,9 @@ const TabContent = ({
// show quick reply modal // show quick reply modal
const _showQuickReplyModal = (post: any) => { const _showQuickReplyModal = (post: any) => {
if (isLoggedIn) { if (isLoggedIn) {
dispatch(showReplyModal({mode:'comment', parentPost:post})); dispatch(showReplyModal({ mode: 'comment', parentPost: post }));
} else { } else {
//TODO: show proper alert message // TODO: show proper alert message
console.log('Not LoggedIn'); console.log('Not LoggedIn');
} }
}; };

View File

@ -1,12 +1,12 @@
import React from 'react'; import React from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { View, Text } from 'react-native'; import { View, Text } from 'react-native';
import IconButton from '../iconButton';
import Clipboard from '@react-native-clipboard/clipboard'; import Clipboard from '@react-native-clipboard/clipboard';
import { useDispatch } from 'react-redux';
import IconButton from '../iconButton';
// Styles // Styles
import styles from './textBoxWithCopyStyles'; import styles from './textBoxWithCopyStyles';
import { useDispatch } from 'react-redux';
import { toastNotification } from '../../redux/actions/uiAction'; import { toastNotification } from '../../redux/actions/uiAction';
interface TextBoxWithCopyProps { interface TextBoxWithCopyProps {
@ -23,7 +23,7 @@ const TextBoxWithCopy = ({ label, value, renderSecondButton }: TextBoxWithCopyPr
<View style={styles.container}> <View style={styles.container}>
<View style={styles.labelContainer}> <View style={styles.labelContainer}>
<Text style={styles.inputLabel}>{label}</Text> <Text style={styles.inputLabel}>{label}</Text>
{renderSecondButton ? renderSecondButton : null} {renderSecondButton || null}
</View> </View>
<View style={styles.copyInputContainer}> <View style={styles.copyInputContainer}>
<View style={styles.textValueContainer}> <View style={styles.textValueContainer}>
@ -33,7 +33,7 @@ const TextBoxWithCopy = ({ label, value, renderSecondButton }: TextBoxWithCopyPr
</View> </View>
<IconButton <IconButton
size={20} size={20}
color={'white'} color="white"
style={styles.copyIconStyle} style={styles.copyIconStyle}
name="content-copy" name="content-copy"
iconType="MaterialIcons" iconType="MaterialIcons"

View File

@ -15,7 +15,7 @@ const TransactionView = ({ item, index, cancelling, onCancelPress, onRepeatPress
const intl = useIntl(); const intl = useIntl();
const [collapsed, setCollapsed] = useState(true); const [collapsed, setCollapsed] = useState(true);
const title = !!intl.messages[`wallet.${item.textKey}`] const title = intl.messages[`wallet.${item.textKey}`]
? intl.formatMessage({ ? intl.formatMessage({
id: `wallet.${item.textKey}`, id: `wallet.${item.textKey}`,
}) })

View File

@ -94,7 +94,6 @@ const TransferAccountSelector = ({
} }
const isValid = res.includes(username); const isValid = res.includes(username);
if (isValid) { if (isValid) {
getRecurrentTransferOfUser(username); getRecurrentTransferOfUser(username);
} }

View File

@ -150,7 +150,7 @@ const TransferAmountInputSection = ({
const _onDelete = () => { const _onDelete = () => {
onNext(true); onNext(true);
} };
const _renderDescription = (text) => <Text style={styles.description}>{text}</Text>; const _renderDescription = (text) => <Text style={styles.description}>{text}</Text>;
const _renderCenterDescription = (text, extraStyles = {}) => ( const _renderCenterDescription = (text, extraStyles = {}) => (

View File

@ -51,7 +51,7 @@ import { CacheStatus } from '../../../redux/reducers/cacheReducer';
import showLoginAlert from '../../../utils/showLoginAlert'; import showLoginAlert from '../../../utils/showLoginAlert';
import { delay } from '../../../utils/editor'; import { delay } from '../../../utils/editor';
interface Props { } interface Props {}
interface PopoverOptions { interface PopoverOptions {
anchorRect: Rect; anchorRect: Rect;
content: any; content: any;
@ -66,7 +66,7 @@ interface PopoverOptions {
* *
*/ */
const UpvotePopover = forwardRef(({ }: Props, ref) => { const UpvotePopover = forwardRef(({}: Props, ref) => {
const intl = useIntl(); const intl = useIntl();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -94,7 +94,6 @@ const UpvotePopover = forwardRef(({ }: Props, ref) => {
const [sliderValue, setSliderValue] = useState(1); const [sliderValue, setSliderValue] = useState(1);
const [amount, setAmount] = useState('0.00000'); const [amount, setAmount] = useState('0.00000');
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
showPopover: ({ showPopover: ({
anchorRect: _anchorRect, anchorRect: _anchorRect,
@ -141,19 +140,22 @@ const UpvotePopover = forwardRef(({ }: Props, ref) => {
}, []); }, []);
useEffect(() => { useEffect(() => {
let _upvotePercent = 1; let _upvotePercent = 1;
switch(postType){ switch (postType) {
case PostTypes.POST: _upvotePercent = postUpvotePercent; break; case PostTypes.POST:
case PostTypes.COMMENT: _upvotePercent = commentUpvotePercent; break; _upvotePercent = postUpvotePercent;
case PostTypes.WAVE: _upvotePercent = waveUpvotePercent; break; break;
case PostTypes.COMMENT:
_upvotePercent = commentUpvotePercent;
break;
case PostTypes.WAVE:
_upvotePercent = waveUpvotePercent;
break;
} }
setSliderValue(_upvotePercent) setSliderValue(_upvotePercent);
_calculateEstimatedAmount(_upvotePercent) _calculateEstimatedAmount(_upvotePercent);
}, [content, postType]); }, [content, postType]);
// Component Functions // Component Functions
const _calculateEstimatedAmount = async (value: number = sliderValue) => { const _calculateEstimatedAmount = async (value: number = sliderValue) => {
if (currentAccount && Object.entries(currentAccount).length !== 0) { if (currentAccount && Object.entries(currentAccount).length !== 0) {
@ -204,7 +206,13 @@ const UpvotePopover = forwardRef(({ }: Props, ref) => {
return; return;
} }
setIsVoted(!!sliderValue); setIsVoted(!!sliderValue);
_updateVoteCache(_author, _permlink, amount, false, !!sliderValue ? CacheStatus.PUBLISHED : CacheStatus.DELETED); _updateVoteCache(
_author,
_permlink,
amount,
false,
sliderValue ? CacheStatus.PUBLISHED : CacheStatus.DELETED,
);
}) })
.catch((err) => { .catch((err) => {
_updateVoteCache(_author, _permlink, amount, false, CacheStatus.FAILED); _updateVoteCache(_author, _permlink, amount, false, CacheStatus.FAILED);
@ -267,7 +275,13 @@ const UpvotePopover = forwardRef(({ }: Props, ref) => {
transactionId: response.id, transactionId: response.id,
}); });
setIsVoted(!!sliderValue); setIsVoted(!!sliderValue);
_updateVoteCache(_author, _permlink, amount, true, !!sliderValue ? CacheStatus.PUBLISHED : CacheStatus.DELETED); _updateVoteCache(
_author,
_permlink,
amount,
true,
sliderValue ? CacheStatus.PUBLISHED : CacheStatus.DELETED,
);
}) })
.catch((err) => { .catch((err) => {
dispatch( dispatch(
@ -286,17 +300,21 @@ const UpvotePopover = forwardRef(({ }: Props, ref) => {
const _setUpvotePercent = (value) => { const _setUpvotePercent = (value) => {
if (value) { if (value) {
let _dispatchAction: any = null;
let _dispatchAction:any = null switch (postType) {
switch(postType){ case PostTypes.POST:
case PostTypes.POST: _dispatchAction = setPostUpvotePercent; break; _dispatchAction = setPostUpvotePercent;
case PostTypes.COMMENT: _dispatchAction = setCommentUpvotePercent; break; break;
case PostTypes.WAVE: _dispatchAction = setWaveUpvotePercent; break; case PostTypes.COMMENT:
_dispatchAction = setCommentUpvotePercent;
break;
case PostTypes.WAVE:
_dispatchAction = setWaveUpvotePercent;
break;
} }
if(_dispatchAction){ if (_dispatchAction) {
dispatch(_dispatchAction(value)) dispatch(_dispatchAction(value));
} }
} }
}; };
@ -311,7 +329,7 @@ const UpvotePopover = forwardRef(({ }: Props, ref) => {
const percent = Math.floor(sliderValue * 10000 * (isDownvote ? -1 : 1)); const percent = Math.floor(sliderValue * 10000 * (isDownvote ? -1 : 1));
const rshares = calculateEstimatedRShares(currentAccount, percent) * (isDownvote ? -1 : 1); const rshares = calculateEstimatedRShares(currentAccount, percent) * (isDownvote ? -1 : 1);
// update redux // update redux
const postPath = `${author || ''}/${permlink || ''}`; const postPath = `${author || ''}/${permlink || ''}`;
const curTime = new Date().getTime(); const curTime = new Date().getTime();
@ -348,7 +366,7 @@ const UpvotePopover = forwardRef(({ }: Props, ref) => {
const sliderColor = isDownVoted ? '#ec8b88' : '#357ce6'; const sliderColor = isDownVoted ? '#ec8b88' : '#357ce6';
const _minSliderVal = isVoted || isDownVoted ? 0 : 0.01 const _minSliderVal = isVoted || isDownVoted ? 0 : 0.01;
return ( return (
<Fragment> <Fragment>

View File

@ -1,7 +1,6 @@
import React from 'react'; import React from 'react';
import { SafeAreaView, FlatList } from 'react-native'; import { SafeAreaView, FlatList } from 'react-native';
// Utils // Utils
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import { getTimeFromNow } from '../../../utils/time'; import { getTimeFromNow } from '../../../utils/time';

View File

@ -112,7 +112,6 @@ const WalletView = ({ setEstimatedWalletValue, selectedUser, handleOnScroll }) =
</Fragment> </Fragment>
)} )}
</ScrollView> </ScrollView>
)} )}
</WalletContainer> </WalletContainer>
); );

View File

@ -1,8 +1,8 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import WebView from 'react-native-webview';
import { useAppDispatch, useAppSelector } from '../../hooks'; import { useAppDispatch, useAppSelector } from '../../hooks';
import { hideWebViewModal } from '../../redux/actions/uiAction'; import { hideWebViewModal } from '../../redux/actions/uiAction';
import WebView from 'react-native-webview';
import { hsOptions } from '../../constants/hsOptions'; import { hsOptions } from '../../constants/hsOptions';
import { Modal } from '..'; import { Modal } from '..';
import styles from './webViewModalStyles'; import styles from './webViewModalStyles';

View File

@ -24,18 +24,17 @@ const DEFAULT_ASSETS = [
symbol: 'HBD', symbol: 'HBD',
notCrypto: false, notCrypto: false,
isEngine: false, isEngine: false,
} },
] as CoinBase[]; ] as CoinBase[];
export enum ASSET_IDS { export enum ASSET_IDS {
ECENCY= 'ecency', ECENCY = 'ecency',
HIVE = 'hive', HIVE = 'hive',
HBD = 'hive_dollar', HBD = 'hive_dollar',
HP = 'hive_power', HP = 'hive_power',
SPK = 'SPK', SPK = 'SPK',
LARYNX = 'LARYNX', LARYNX = 'LARYNX',
LARYNX_POWER = 'LP' LARYNX_POWER = 'LP',
}; }
export default DEFAULT_ASSETS; export default DEFAULT_ASSETS;

View File

@ -15,12 +15,12 @@ export const VALUE = [
]; ];
export const SERVER_LIST = [ export const SERVER_LIST = [
"https://rpc.ecency.com", 'https://rpc.ecency.com',
"https://api.hive.blog", 'https://api.hive.blog',
"https://api.deathwing.me", 'https://api.deathwing.me',
"https://api.pharesim.me", 'https://api.pharesim.me',
"https://anyx.io", 'https://anyx.io',
"https://rpc.ausbit.dev", 'https://rpc.ausbit.dev',
"https://api.openhive.network", 'https://api.openhive.network',
"https://api.hivekings.com" 'https://api.hivekings.com',
]; ];

View File

@ -19,7 +19,7 @@ export default {
icon: 'trophy-outline', icon: 'trophy-outline',
textKey: 'community_reward', textKey: 'community_reward',
iconType: 'MaterialCommunityIcons', iconType: 'MaterialCommunityIcons',
point: 0.1 point: 0.1,
}, },
160: { 160: {
icon: 'target', icon: 'target',
@ -93,7 +93,7 @@ export default {
iconType: 'MaterialCommunityIcons', iconType: 'MaterialCommunityIcons',
point: 10, point: 10,
}, },
'default': { default: {
icon: 'local-activity', icon: 'local-activity',
textKey: 'points_activity', textKey: 'points_activity',
iconType: 'MaterialIcons', iconType: 'MaterialIcons',

View File

@ -1,5 +1,5 @@
export enum PostTypes { export enum PostTypes {
POST = 'post', POST = 'post',
COMMENT = 'comment', COMMENT = 'comment',
WAVE = 'wave' WAVE = 'wave',
} }

View File

@ -39,7 +39,6 @@ const ROUTES = {
WELCOME: `Welcome${SCREEN_SUFFIX}`, WELCOME: `Welcome${SCREEN_SUFFIX}`,
BACKUP_KEYS: `BackupKeys${SCREEN_SUFFIX}`, BACKUP_KEYS: `BackupKeys${SCREEN_SUFFIX}`,
TRADE: `Trade${SCREEN_SUFFIX}`, TRADE: `Trade${SCREEN_SUFFIX}`,
}, },
MODALS: { MODALS: {
ASSETS_SELECT: `AssetsSelect${MODAL_SUFFIX}`, ASSETS_SELECT: `AssetsSelect${MODAL_SUFFIX}`,

View File

@ -484,7 +484,6 @@ class ProfileContainer extends Component {
if (isLoggedIn && !nextProps.isLoggedIn) { if (isLoggedIn && !nextProps.isLoggedIn) {
navigation.navigate(ROUTES.SCREENS.LOGIN); navigation.navigate(ROUTES.SCREENS.LOGIN);
return;
} }
} }

View File

@ -60,7 +60,6 @@ export const BottomTabNavigator = () => {
iconName: 'notifications', // read in bottomTabBarView iconName: 'notifications', // read in bottomTabBarView
}} }}
/> />
</Tab.Navigator> </Tab.Navigator>
); );
}; };

View File

@ -24,7 +24,7 @@ export const fetchMarketChart = async (
interval, interval,
}; };
/** /**
* NOTE: skipping this failsafe since for now we can only use 'daily' interval * NOTE: skipping this failsafe since for now we can only use 'daily' interval
// failsafe for accidental invalid parameters // failsafe for accidental invalid parameters
// ref: https://www.coingecko.com/en/api/documentation // ref: https://www.coingecko.com/en/api/documentation

View File

@ -11,7 +11,6 @@ export const convertChartItem = (rawData: any) => {
}; };
export const convertMarketData = (rawData: any) => { export const convertMarketData = (rawData: any) => {
return { return {
prices: rawData.prices ? rawData.prices.map(convertChartItem) : [], prices: rawData.prices ? rawData.prices.map(convertChartItem) : [],
marketCaps: rawData.market_caps ? rawData.market_caps.map(convertChartItem) : [], marketCaps: rawData.market_caps ? rawData.market_caps.map(convertChartItem) : [],

View File

@ -6,7 +6,7 @@ import {
LatestQuotes, LatestQuotes,
QuoteItem, QuoteItem,
ReferralStat, ReferralStat,
Draft Draft,
} from './ecency.types'; } from './ecency.types';
export const convertReferral = (rawData: any) => { export const convertReferral = (rawData: any) => {
@ -14,7 +14,7 @@ export const convertReferral = (rawData: any) => {
_id: rawData.id || 0, _id: rawData.id || 0,
referral: rawData.referral || '', referral: rawData.referral || '',
referredUsername: rawData.username || '', referredUsername: rawData.username || '',
isRewarded: rawData.rewarded ? true : false, isRewarded: !!rawData.rewarded,
timestamp: new Date(rawData.created) || new Date(), timestamp: new Date(rawData.created) || new Date(),
} as Referral; } as Referral;
}; };
@ -37,23 +37,23 @@ export const convertQuoteItem = (rawData: any, currencyRate: number) => {
} as QuoteItem; } as QuoteItem;
}; };
export const convertDraft = (rawData:any) => { export const convertDraft = (rawData: any) => {
if(!rawData){ if (!rawData) {
return null return null;
} }
return { return {
_id:rawData._id, _id: rawData._id,
title:rawData.title, title: rawData.title,
body:rawData.body, body: rawData.body,
tags_arr:rawData.tags_arr, tags_arr: rawData.tags_arr,
tags:rawData.tags, tags: rawData.tags,
meta:rawData.meta, meta: rawData.meta,
modified:rawData.modified, modified: rawData.modified,
created:rawData.created, created: rawData.created,
timestamp:rawData.timestamp timestamp: rawData.timestamp,
} as Draft } as Draft;
} };
export const convertLatestQuotes = (rawData: any, currencyRate: number) => { export const convertLatestQuotes = (rawData: any, currencyRate: number) => {
return { return {

View File

@ -10,7 +10,7 @@ import { EcencyUser, UserPoint } from './ecency.types';
* @param tx transaction id * @param tx transaction id
* @returns * @returns
*/ */
export const userActivity = async (ty: number, tx: string = '', bl: string | number = '') => { export const userActivity = async (ty: number, tx = '', bl: string | number = '') => {
try { try {
const data: { const data: {
ty: number; ty: number;

View File

@ -31,13 +31,13 @@ import {
* ************************************ * ************************************
*/ */
export const getFiatHbdRate = (fiatCode:string) => export const getFiatHbdRate = (fiatCode: string) =>
ecencyApi ecencyApi
.get(`/private-api/market-data/${fiatCode}/hbd`) .get(`/private-api/market-data/${fiatCode}/hbd`)
.then((resp) => resp.data) .then((resp) => resp.data)
.catch((err) => { .catch((err) => {
bugsnagInstance.notify(err); bugsnagInstance.notify(err);
//TODO: save currency rate of offline values // TODO: save currency rate of offline values
return 1; return 1;
}); });
@ -53,7 +53,7 @@ export const getLatestQuotes = async (currencyRate: number): Promise<LatestMarke
const data = convertLatestQuotes(res.data, currencyRate); const data = convertLatestQuotes(res.data, currencyRate);
console.log('parsed quotes data', data, currencyRate); console.log('parsed quotes data', data, currencyRate);
//TODO fetch engine quotes here // TODO fetch engine quotes here
return data; return data;
} catch (error) { } catch (error) {
@ -126,8 +126,8 @@ export const addDraft = async (draft: Object) => {
const res = await ecencyApi.post('/private-api/drafts-add', newDraft); const res = await ecencyApi.post('/private-api/drafts-add', newDraft);
const rawData = res.data?.drafts; const rawData = res.data?.drafts;
if(!rawData){ if (!rawData) {
throw new Error("Invalid response, drafts data not returned") throw new Error('Invalid response, drafts data not returned');
} }
const data = rawData.length > 0 ? rawData.map(convertDraft) : []; const data = rawData.length > 0 ? rawData.map(convertDraft) : [];
@ -526,7 +526,7 @@ export const searchPath = async (q: string) => {
* @param random random * @param random random
* @returns array of accounts * @returns array of accounts
*/ */
export const searchAccount = async (q: string = '', limit: number = 20, random: number = 0) => { export const searchAccount = async (q = '', limit = 20, random = 0) => {
try { try {
const data = { const data = {
q, q,
@ -549,7 +549,7 @@ export const searchAccount = async (q: string = '', limit: number = 20, random:
* @param random random * @param random random
* @returns array of accounts * @returns array of accounts
*/ */
export const searchTag = async (q: string = '', limit: number = 20, random: number = 0) => { export const searchTag = async (q = '', limit = 20, random = 0) => {
try { try {
const data = { const data = {
q, q,
@ -782,7 +782,7 @@ export const getPromotedEntries = async (username: string) => {
* post inapp purchase method to call * post inapp purchase method to call
* @param data PurchaseRequestData * @param data PurchaseRequestData
* @returns * @returns
**/ * */
export const purchaseOrder = (data: PurchaseRequestData) => export const purchaseOrder = (data: PurchaseRequestData) =>
api api
.post('/purchase-order', data) .post('/purchase-order', data)

View File

@ -1,7 +1,20 @@
import {
EngineMetric,
HistoryItem,
HiveEngineToken,
MarketData,
Token,
TokenBalance,
TokenMetadata,
TokenStatus,
} from './hiveEngine.types';
import { EngineMetric, HistoryItem, HiveEngineToken, MarketData, Token, TokenBalance, TokenMetadata, TokenStatus } from './hiveEngine.types'; export const convertEngineToken = (
balanceObj: TokenBalance,
export const convertEngineToken = (balanceObj: TokenBalance, token?: Token, metrics?: EngineMetric, tokenStatus?:TokenStatus) => { token?: Token,
metrics?: EngineMetric,
tokenStatus?: TokenStatus,
) => {
if (!balanceObj) { if (!balanceObj) {
return null; return null;
} }
@ -37,50 +50,44 @@ export const convertEngineToken = (balanceObj: TokenBalance, token?: Token, metr
} as HiveEngineToken; } as HiveEngineToken;
}; };
export const convertRewardsStatus = (rawData: any) => { export const convertRewardsStatus = (rawData: any) => {
return { return {
symbol:rawData.symbol, symbol: rawData.symbol,
pendingToken:rawData.pending_token, pendingToken: rawData.pending_token,
precision:rawData.precision, precision: rawData.precision,
pendingRewards: rawData.pending_token / Math.pow(10, rawData.precision) pendingRewards: rawData.pending_token / Math.pow(10, rawData.precision),
} as TokenStatus } as TokenStatus;
} };
export const convertMarketData = (rawData: any) => { export const convertMarketData = (rawData: any) => {
if (!rawData) {
if(!rawData){
return null; return null;
} }
return { return {
quoteVolume:parseFloat(rawData.quoteVolume), quoteVolume: parseFloat(rawData.quoteVolume),
baseVolume:parseFloat(rawData.baseVolume), baseVolume: parseFloat(rawData.baseVolume),
low:parseFloat(rawData.low), low: parseFloat(rawData.low),
close:parseFloat(rawData.close), close: parseFloat(rawData.close),
high:parseFloat(rawData.high), high: parseFloat(rawData.high),
open:parseFloat(rawData.open), open: parseFloat(rawData.open),
timestamp:rawData.timestamp, timestamp: rawData.timestamp,
} as MarketData } as MarketData;
} };
export const convertEngineHistory = (rawData: any) => { export const convertEngineHistory = (rawData: any) => {
return { return {
_id: rawData._id,
_id:rawData._id, blockNumber: rawData.blockNumber,
blockNumber:rawData.blockNumber, transactionId: rawData.transactionId,
transactionId:rawData.transactionId, timestamp: rawData.timestamp * 1000,
timestamp:rawData.timestamp * 1000, operation: rawData.operation,
operation:rawData.operation, from: rawData.from,
from:rawData.from, to: rawData.to,
to:rawData.to, symbol: rawData.symbol,
symbol:rawData.symbol, quantity: parseFloat(rawData.quantity),
quantity:parseFloat(rawData.quantity), memo: rawData.memo,
memo:rawData.memo, account: rawData.account,
account:rawData.account, authorperm: rawData.authorperm,
authorperm:rawData.authorperm, } as HistoryItem;
} as HistoryItem };
}

View File

@ -1,5 +1,3 @@
import { import {
EngineContracts, EngineContracts,
EngineIds, EngineIds,
@ -15,7 +13,12 @@ import {
MarketData, MarketData,
HistoryItem, HistoryItem,
} from './hiveEngine.types'; } from './hiveEngine.types';
import { convertEngineToken, convertRewardsStatus, convertMarketData, convertEngineHistory } from './converters'; import {
convertEngineToken,
convertRewardsStatus,
convertMarketData,
convertEngineHistory,
} from './converters';
import bugsnapInstance from '../../config/bugsnag'; import bugsnapInstance from '../../config/bugsnag';
import ecencyApi from '../../config/ecencyApi'; import ecencyApi from '../../config/ecencyApi';
@ -26,19 +29,17 @@ import ecencyApi from '../../config/ecencyApi';
*/ */
const PATH_ENGINE_CONTRACTS = '/private-api/engine-api'; const PATH_ENGINE_CONTRACTS = '/private-api/engine-api';
//proxied path for 'https://scot-api.hive-engine.com/'; // proxied path for 'https://scot-api.hive-engine.com/';
const PATH_ENGINE_REWARDS = '/private-api/engine-reward-api'; const PATH_ENGINE_REWARDS = '/private-api/engine-reward-api';
//proxied path for 'https://info-api.tribaldex.com/market/ohlcv'; // proxied path for 'https://info-api.tribaldex.com/market/ohlcv';
const PATH_ENGINE_CHART = '/private-api/engine-chart-api'; const PATH_ENGINE_CHART = '/private-api/engine-chart-api';
//sample hive history endpoint call // sample hive history endpoint call
//docs: https://github.com/hive-engine/ssc_tokens_history/tree/hive#api-usage // docs: https://github.com/hive-engine/ssc_tokens_history/tree/hive#api-usage
//example: https://history.hive-engine.com/accountHistory?account=demo.com&limit=10&offset=10 // example: https://history.hive-engine.com/accountHistory?account=demo.com&limit=10&offset=10
const PATH_ENGINE_ACCOUNT_HISTORY = '/private-api/engine-account-history'; const PATH_ENGINE_ACCOUNT_HISTORY = '/private-api/engine-account-history';
export const fetchTokenBalances = (account: string): Promise<TokenBalance[]> => { export const fetchTokenBalances = (account: string): Promise<TokenBalance[]> => {
const data: EngineRequestPayload = { const data: EngineRequestPayload = {
jsonrpc: JSON_RPC.RPC_2, jsonrpc: JSON_RPC.RPC_2,
@ -47,13 +48,14 @@ export const fetchTokenBalances = (account: string): Promise<TokenBalance[]> =>
contract: EngineContracts.TOKENS, contract: EngineContracts.TOKENS,
table: EngineTables.BALANCES, table: EngineTables.BALANCES,
query: { query: {
account: account, account,
}, },
}, },
id: EngineIds.ONE, id: EngineIds.ONE,
}; };
return ecencyApi.post(PATH_ENGINE_CONTRACTS, data) return ecencyApi
.post(PATH_ENGINE_CONTRACTS, data)
.then((r) => r.data.result) .then((r) => r.data.result)
.catch((e) => { .catch((e) => {
return []; return [];
@ -86,17 +88,14 @@ export const fetchHiveEngineTokenBalances = async (
account: string, account: string,
): Promise<Array<HiveEngineToken | null>> => { ): Promise<Array<HiveEngineToken | null>> => {
try { try {
const balances = await fetchTokenBalances(account); const balances = await fetchTokenBalances(account);
const symbols = balances.map((t) => t.symbol); const symbols = balances.map((t) => t.symbol);
const tokens = await fetchTokens(symbols); const tokens = await fetchTokens(symbols);
const metrices = await fetchMetics(symbols); const metrices = await fetchMetics(symbols);
const unclaimed = await fetchUnclaimedRewards(account) const unclaimed = await fetchUnclaimedRewards(account);
return balances.map((balance) => { return balances.map((balance) => {
const token = tokens.find((t) => t.symbol == balance.symbol); const token = tokens.find((t) => t.symbol == balance.symbol);
const metrics = metrices.find((t) => t.symbol == balance.symbol); const metrics = metrices.find((t) => t.symbol == balance.symbol);
const pendingRewards = unclaimed.find((t) => t.symbol == balance.symbol); const pendingRewards = unclaimed.find((t) => t.symbol == balance.symbol);
@ -109,11 +108,8 @@ export const fetchHiveEngineTokenBalances = async (
} }
}; };
export const fetchMetics = async (tokens?: string[]) => { export const fetchMetics = async (tokens?: string[]) => {
try { try {
const data = { const data = {
jsonrpc: JSON_RPC.RPC_2, jsonrpc: JSON_RPC.RPC_2,
method: Methods.FIND, method: Methods.FIND,
@ -122,94 +118,101 @@ export const fetchMetics = async (tokens?: string[]) => {
table: EngineTables.METRICS, table: EngineTables.METRICS,
query: { query: {
symbol: { $in: tokens }, symbol: { $in: tokens },
} },
}, },
id: EngineIds.ONE id: EngineIds.ONE,
}; };
const response = await ecencyApi.post(PATH_ENGINE_CONTRACTS, data) const response = await ecencyApi.post(PATH_ENGINE_CONTRACTS, data);
if (!response.data.result) { if (!response.data.result) {
throw new Error("No metric data returned") throw new Error('No metric data returned');
} }
return response.data.result as EngineMetric[] return response.data.result as EngineMetric[];
} catch (err) { } catch (err) {
console.warn('Failed to get engine metrices', err); console.warn('Failed to get engine metrices', err);
bugsnapInstance.notify(err); bugsnapInstance.notify(err);
throw err; throw err;
} }
} };
export const fetchUnclaimedRewards = async (account: string): Promise<TokenStatus[]> => { export const fetchUnclaimedRewards = async (account: string): Promise<TokenStatus[]> => {
try { try {
const response = await ecencyApi.get(`${PATH_ENGINE_REWARDS}/${account}`, { const response = await ecencyApi.get(`${PATH_ENGINE_REWARDS}/${account}`, {
params:{hive:1} params: { hive: 1 },
}) });
const rawData = Object.values(response.data) const rawData = Object.values(response.data);
if (!rawData || rawData.length === 0) { if (!rawData || rawData.length === 0) {
throw new Error("No rewards data returned"); throw new Error('No rewards data returned');
} }
const data = rawData.map(convertRewardsStatus); const data = rawData.map(convertRewardsStatus);
const filteredData = data.filter(item => item && item.pendingToken > 0) const filteredData = data.filter((item) => item && item.pendingToken > 0);
console.log('unclaimed engine rewards data', filteredData); console.log('unclaimed engine rewards data', filteredData);
return filteredData; return filteredData;
} catch (err) { } catch (err) {
console.warn("failed ot get unclaimed engine rewards", err) console.warn('failed ot get unclaimed engine rewards', err);
bugsnapInstance.notify(err); bugsnapInstance.notify(err);
return []; return [];
} }
}; };
export const fetchEngineMarketData = async (symbol: any, vsCurrency:string = 'usd', days:number = 0, interval = 'daily') => { export const fetchEngineMarketData = async (
symbol: any,
vsCurrency = 'usd',
days = 0,
interval = 'daily',
) => {
try { try {
const response = await ecencyApi.get(PATH_ENGINE_CHART, { const response = await ecencyApi.get(PATH_ENGINE_CHART, {
params: { symbol, interval } params: { symbol, interval },
}); });
const rawData = response?.data; const rawData = response?.data;
if(!rawData){ if (!rawData) {
throw new Error("No data returned"); throw new Error('No data returned');
} }
const data:MarketData[] = rawData.map(convertMarketData); const data: MarketData[] = rawData.map(convertMarketData);
return days > 1 && data.length > days ? data.slice(data.length - days) : data; return days > 1 && data.length > days ? data.slice(data.length - days) : data;
} catch (err) { } catch (err) {
bugsnapInstance.notify(err); bugsnapInstance.notify(err);
console.warn("failed to get chart data", err.message); console.warn('failed to get chart data', err.message);
return [] return [];
} }
}; };
export const fetchEngineAccountHistory = async (
export const fetchEngineAccountHistory = async (username:string , symbol:string , startIndex:number = 0, limit:number = 20) => { username: string,
symbol: string,
startIndex = 0,
limit = 20,
) => {
try { try {
const response = await ecencyApi.get(PATH_ENGINE_ACCOUNT_HISTORY, {params:{ const response = await ecencyApi.get(PATH_ENGINE_ACCOUNT_HISTORY, {
account:username, params: {
symbol:symbol, account: username,
limit, symbol,
offset: limit * startIndex limit,
}}) offset: limit * startIndex,
},
});
const rawData = response?.data; const rawData = response?.data;
if(!rawData){ if (!rawData) {
throw new Error("No data returned"); throw new Error('No data returned');
} }
const data:HistoryItem[] = rawData.map(convertEngineHistory); const data: HistoryItem[] = rawData.map(convertEngineHistory);
return data; return data;
} catch (err) { } catch (err) {
bugsnapInstance.notify(err); bugsnapInstance.notify(err);
console.warn("failed to get engine account history", err.message); console.warn('failed to get engine account history', err.message);
return [] return [];
} }
} };

View File

@ -9,7 +9,7 @@ export enum JSON_RPC {
export enum EngineContracts { export enum EngineContracts {
TOKENS = 'tokens', TOKENS = 'tokens',
MARKET = 'market' MARKET = 'market',
} }
export enum EngineActions { export enum EngineActions {
@ -17,10 +17,9 @@ export enum EngineActions {
DELEGATE = 'delegate', DELEGATE = 'delegate',
UNDELEGATE = 'undelegate', UNDELEGATE = 'undelegate',
UNSTAKE = 'unstake', UNSTAKE = 'unstake',
STAKE = 'stake' STAKE = 'stake',
} }
export enum EngineTables { export enum EngineTables {
BALANCES = 'balances', BALANCES = 'balances',
DELEGATIONS = 'delegations', DELEGATIONS = 'delegations',
@ -32,7 +31,6 @@ export enum EngineIds {
ONE = '1', ONE = '1',
} }
export interface TokenBalance { export interface TokenBalance {
symbol: string; symbol: string;
balance: string; balance: string;
@ -79,7 +77,7 @@ export interface HiveEngineToken {
tokenPrice?: number; tokenPrice?: number;
percentChange?: number; percentChange?: number;
unclaimedBalance: string; unclaimedBalance: string;
volume24h?:number volume24h?: number;
} }
export interface TokenMetadata { export interface TokenMetadata {
@ -95,21 +93,18 @@ export interface TokenStatus {
pendingRewards: number; pendingRewards: number;
} }
export interface EngineMetric { export interface EngineMetric {
_id: number _id: number;
highestBid: string; highestBid: string;
lastDayPrice: string; lastDayPrice: string;
lastDayPriceExpiration: number; lastDayPriceExpiration: number;
lastPrice: string; lastPrice: string;
lowestAsk: string; lowestAsk: string;
priceChangeHive:string; priceChangeHive: string;
priceChangePercent:string; priceChangePercent: string;
symbol: string; symbol: string;
volume: string; volume: string;
volumeExpiration: number; volumeExpiration: number;
} }
interface EngineQuery { interface EngineQuery {
@ -130,105 +125,102 @@ export interface EngineRequestPayload {
id: EngineIds; id: EngineIds;
} }
export interface EngineActionPayload { export interface EngineActionPayload {
to:string, to: string;
symbol:string, symbol: string;
quantity:string, quantity: string;
memo?:string memo?: string;
} }
export interface EngineActionJSON { export interface EngineActionJSON {
contractName:EngineContracts; contractName: EngineContracts;
contractAction:EngineActions; contractAction: EngineActions;
contractPayload: EngineActionPayload; contractPayload: EngineActionPayload;
} }
export interface MarketData { export interface MarketData {
quoteVolume:number; quoteVolume: number;
baseVolume:number; baseVolume: number;
low:number; low: number;
close:number; close: number;
high:number; high: number;
open:number; open: number;
timestamp:number; timestamp: number;
} }
export interface HistoryItem { export interface HistoryItem {
_id:string; _id: string;
blockNumber:number; blockNumber: number;
transactionId:string; transactionId: string;
timestamp:number; timestamp: number;
operation:EngineOperations; operation: EngineOperations;
from:string; from: string;
to:string; to: string;
symbol:string; symbol: string;
quantity:number; quantity: number;
memo:string; memo: string;
account:string; account: string;
authorperm?:string; authorperm?: string;
} }
export enum EngineOperations { export enum EngineOperations {
TOKENS_CREATE = "tokens_create", TOKENS_CREATE = 'tokens_create',
TOKENS_ISSUE = "tokens_issue", TOKENS_ISSUE = 'tokens_issue',
TOKENS_TRANSFER = "tokens_transfer", TOKENS_TRANSFER = 'tokens_transfer',
TOKENS_TRANSFER_TO_CONTRACT = "tokens_transferToContract", TOKENS_TRANSFER_TO_CONTRACT = 'tokens_transferToContract',
TOKENS_TRANSFER_FROM_CONTRACT = "tokens_transferFromContract", TOKENS_TRANSFER_FROM_CONTRACT = 'tokens_transferFromContract',
TOKENS_UPDATE_PRECISION = "tokens_updatePrecision", TOKENS_UPDATE_PRECISION = 'tokens_updatePrecision',
TOKENS_UPDATE_URL = "tokens_updateUrl", TOKENS_UPDATE_URL = 'tokens_updateUrl',
TOKENS_UPDATE_METADATA = "tokens_updateMetadata", TOKENS_UPDATE_METADATA = 'tokens_updateMetadata',
TOKENS_TRANSFER_OWNERSHIP = "tokens_transferOwnership", TOKENS_TRANSFER_OWNERSHIP = 'tokens_transferOwnership',
TOKENS_ENABLE_STAKING = "tokens_enableStaking", TOKENS_ENABLE_STAKING = 'tokens_enableStaking',
TOKENS_ENABLE_DELEGATION = "tokens_enableDelegation", TOKENS_ENABLE_DELEGATION = 'tokens_enableDelegation',
TOKENS_STAKE = "tokens_stake", TOKENS_STAKE = 'tokens_stake',
TOKENS_UNSTAKE_START = "tokens_unstakeStart", TOKENS_UNSTAKE_START = 'tokens_unstakeStart',
TOKENS_UNSTAKE_DONE = "tokens_unstakeDone", TOKENS_UNSTAKE_DONE = 'tokens_unstakeDone',
TOKENS_CANCEL_UNSTAKE = "tokens_cancelUnstake", TOKENS_CANCEL_UNSTAKE = 'tokens_cancelUnstake',
TOKENS_DELEGATE = "tokens_delegate", TOKENS_DELEGATE = 'tokens_delegate',
TOKENS_UNDELEGATE_START = "tokens_undelegateStart", TOKENS_UNDELEGATE_START = 'tokens_undelegateStart',
TOKENS_UNDELEGATE_DONE = "tokens_undelegateDone", TOKENS_UNDELEGATE_DONE = 'tokens_undelegateDone',
TOKENS_TRANSFER_FEE = "tokens_transferFee", TOKENS_TRANSFER_FEE = 'tokens_transferFee',
MARKET_CANCEL = "market_cancel", MARKET_CANCEL = 'market_cancel',
MARKET_PLACE_ORDER = "market_placeOrder", MARKET_PLACE_ORDER = 'market_placeOrder',
MARKET_EXPIRE = "market_expire", MARKET_EXPIRE = 'market_expire',
MARKET_BUY = "market_buy", MARKET_BUY = 'market_buy',
MARKET_BUY_REMAINING = "market_buyRemaining", MARKET_BUY_REMAINING = 'market_buyRemaining',
MARKET_SELL = "market_sell", MARKET_SELL = 'market_sell',
MARKET_SELL_REMAINING = "market_sellRemaining", MARKET_SELL_REMAINING = 'market_sellRemaining',
MARKET_CLOSE = "market_close", MARKET_CLOSE = 'market_close',
MINING_LOTTERY = "mining_lottery", MINING_LOTTERY = 'mining_lottery',
WITNESSES_PROPOSE_ROUND = "witnesses_proposeRound", WITNESSES_PROPOSE_ROUND = 'witnesses_proposeRound',
HIVEPEGGED_BUY = "hivepegged_buy", HIVEPEGGED_BUY = 'hivepegged_buy',
HIVEPEGGED_WITHDRAW = "hivepegged_withdraw", HIVEPEGGED_WITHDRAW = 'hivepegged_withdraw',
INFLATION_ISSUE_NEW_TOKENS = "inflation_issueNewTokens", INFLATION_ISSUE_NEW_TOKENS = 'inflation_issueNewTokens',
NFT_TRANSFER = "nft_transfer", NFT_TRANSFER = 'nft_transfer',
NFT_ISSUE = "nft_issue", NFT_ISSUE = 'nft_issue',
NFT_ISSUE_MULTIPLE = "nft_issueMultiple", NFT_ISSUE_MULTIPLE = 'nft_issueMultiple',
NFT_BURN = "nft_burn", NFT_BURN = 'nft_burn',
NFT_DELEGATE = "nft_delegate", NFT_DELEGATE = 'nft_delegate',
NFT_UNDELEGATE = "nft_undelegate", NFT_UNDELEGATE = 'nft_undelegate',
NFT_UNDELEGATE_DONE = "nft_undelegateDone", NFT_UNDELEGATE_DONE = 'nft_undelegateDone',
NFT_ENABLE_DELEGATION = "nft_enableDelegation", NFT_ENABLE_DELEGATION = 'nft_enableDelegation',
NFT_CREATE = "nft_create", NFT_CREATE = 'nft_create',
NFT_ADD_AUTHORIZED_ISSUING_ACCOUNTS = "nft_addAuthorizedIssuingAccounts", NFT_ADD_AUTHORIZED_ISSUING_ACCOUNTS = 'nft_addAuthorizedIssuingAccounts',
NFT_SET_GROUP_BY = "nft_setGroupBy", NFT_SET_GROUP_BY = 'nft_setGroupBy',
NFT_SET_PROPERTIES = "nft_setProperties", NFT_SET_PROPERTIES = 'nft_setProperties',
NFT_ADD_PROPERTY = "nft_addProperty", NFT_ADD_PROPERTY = 'nft_addProperty',
NFT_SET_PROPERTY_PERMISSIONS = "nft_setPropertyPermissions", NFT_SET_PROPERTY_PERMISSIONS = 'nft_setPropertyPermissions',
NFT_UPDATE_PROPERTY_DEFINITION = "nft_updatePropertyDefinition", NFT_UPDATE_PROPERTY_DEFINITION = 'nft_updatePropertyDefinition',
NFT_UPDATE_URL = "nft_updateUrl", NFT_UPDATE_URL = 'nft_updateUrl',
NFT_UPDATE_METADATA = "nft_updateMetadata", NFT_UPDATE_METADATA = 'nft_updateMetadata',
NFT_UPDATE_NAME = "nft_updateName", NFT_UPDATE_NAME = 'nft_updateName',
NFT_UPDATE_ORG_NAME = "nft_updateOrgName", NFT_UPDATE_ORG_NAME = 'nft_updateOrgName',
NFT_UPDATE_PRODUCT_NAME = "nft_updateProductName", NFT_UPDATE_PRODUCT_NAME = 'nft_updateProductName',
NFT_TRANSFER_FEE = "nft_transferFee", NFT_TRANSFER_FEE = 'nft_transferFee',
NFTMARKET_BUY = "nftmarket_buy", NFTMARKET_BUY = 'nftmarket_buy',
NFTMARKET_TRANSFER_FEE = "nftmarket_transferFee", NFTMARKET_TRANSFER_FEE = 'nftmarket_transferFee',
NFTMARKET_SELL = "nftmarket_sell", NFTMARKET_SELL = 'nftmarket_sell',
NFTMARKET_CANCEL = "nftmarket_cancel", NFTMARKET_CANCEL = 'nftmarket_cancel',
NFTMARKET_CHANGE_PRICE = "nftmarket_changePrice", NFTMARKET_CHANGE_PRICE = 'nftmarket_changePrice',
NFTMARKET_ENABLE_MARKET = "nftmarket_enableMarket" NFTMARKET_ENABLE_MARKET = 'nftmarket_enableMarket',
} }

View File

@ -70,13 +70,7 @@ export const limitOrderCreate = (
); );
}; };
export const limitOrderCancel = (currentAccount: any, pinHash: string, orderid: number) => {
export const limitOrderCancel = (
currentAccount: any,
pinHash:string,
orderid: number
) => {
const digitPinCode = getDigitPinCode(pinHash); const digitPinCode = getDigitPinCode(pinHash);
const key = getAnyPrivateKey( const key = getAnyPrivateKey(
{ {
@ -87,13 +81,13 @@ export const limitOrderCancel = (
if (key) { if (key) {
const privateKey = PrivateKey.fromString(key); const privateKey = PrivateKey.fromString(key);
const ops:Operation[] = [ const ops: Operation[] = [
[ [
"limit_order_cancel", 'limit_order_cancel',
{ {
owner: currentAccount.username, owner: currentAccount.username,
orderid: orderid orderid,
} },
], ],
]; ];
@ -113,8 +107,6 @@ export const limitOrderCancel = (
); );
}; };
export const generateHsLimitOrderCreatePath = ( export const generateHsLimitOrderCreatePath = (
currentAccount: any, currentAccount: any,
amountToSell: number, amountToSell: number,

View File

@ -2154,8 +2154,8 @@ export const resolveTransaction = async (parsedTx, parsedParams, signer) => {
signers: [signer], signers: [signer],
preferred_signer: signer, preferred_signer: signer,
}); });
tx.ref_block_num = parseInt(tx.ref_block_num + '', 10); tx.ref_block_num = parseInt(`${tx.ref_block_num}`, 10);
tx.ref_block_prefix = parseInt(tx.ref_block_prefix + '', 10); tx.ref_block_prefix = parseInt(`${tx.ref_block_prefix}`, 10);
return tx; return tx;
}; };

View File

@ -111,8 +111,8 @@ export interface SavingsWithdrawRequest {
} }
export interface TransferDataType { export interface TransferDataType {
fundType:string, fundType: string;
destination:string destination: string;
amount: string amount: string;
memo?:string memo?: string;
} }

View File

@ -33,7 +33,7 @@ interface MediaUploadVars {
addToUploads: boolean; addToUploads: boolean;
} }
/** GET QUERIES **/ /** GET QUERIES * */
export const useMediaQuery = () => { export const useMediaQuery = () => {
const intl = useIntl(); const intl = useIntl();
@ -57,7 +57,7 @@ export const useSnippetsQuery = () => {
}); });
}; };
/** ADD UPDATE MUTATIONS **/ /** ADD UPDATE MUTATIONS * */
export const useAddToUploadsMutation = () => { export const useAddToUploadsMutation = () => {
const intl = useIntl(); const intl = useIntl();
@ -71,7 +71,7 @@ export const useAddToUploadsMutation = () => {
}, },
onError: (error) => { onError: (error) => {
if (error.toString().includes('code 409')) { if (error.toString().includes('code 409')) {
//means image ware already preset, refresh to get updated order // means image ware already preset, refresh to get updated order
queryClient.invalidateQueries([QUERIES.MEDIA.GET]); queryClient.invalidateQueries([QUERIES.MEDIA.GET]);
} else { } else {
dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' })));
@ -234,7 +234,7 @@ export const useSnippetsMutation = () => {
); );
}; };
/** DELETE MUTATIONS **/ /** DELETE MUTATIONS * */
export const useMediaDeleteMutation = () => { export const useMediaDeleteMutation = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();

View File

@ -10,7 +10,7 @@ export const initQueryClient = () => {
}); });
const client = new QueryClient({ const client = new QueryClient({
//Query client configurations go here... // Query client configurations go here...
defaultOptions: { defaultOptions: {
queries: { queries: {
cacheTime: 1000 * 60 * 60 * 24 * 6, // 7 days cache timer cacheTime: 1000 * 60 * 60 * 24 * 6, // 7 days cache timer
@ -18,34 +18,32 @@ export const initQueryClient = () => {
}, },
}); });
const _shouldDehdrateQuery = (query: Query) => {
const _shouldDehdrateQuery = (query:Query) => {
const _isSuccess = query.state.status === 'success'; const _isSuccess = query.state.status === 'success';
if(_isSuccess){ if (_isSuccess) {
//Cherry pick whihc queries to dehydrate for persistance // Cherry pick whihc queries to dehydrate for persistance
switch(query.queryKey[0]){ switch (query.queryKey[0]) {
case QUERIES.WAVES.GET: case QUERIES.WAVES.GET:
return query.queryKey[3] === 0 //only dehydrate first page of waves return query.queryKey[3] === 0; // only dehydrate first page of waves
case QUERIES.NOTIFICATIONS.GET: case QUERIES.NOTIFICATIONS.GET:
return query.queryKey[2] === '' //only dehydrate first page of notifications return query.queryKey[2] === ''; // only dehydrate first page of notifications
default: default:
return true; return true;
} }
} }
console.log("status error for dehydration", query.queryKey) console.log('status error for dehydration', query.queryKey);
return false; return false;
} };
return { return {
client, client,
persistOptions: { persistOptions: {
persister: asyncStoragePersister, dehydrateOptions: { persister: asyncStoragePersister,
shouldDehydrateQuery: _shouldDehdrateQuery dehydrateOptions: {
} shouldDehydrateQuery: _shouldDehdrateQuery,
},
}, },
} as PersistQueryClientProviderProps; } as PersistQueryClientProviderProps;
}; };
@ -56,4 +54,4 @@ export * from './editorQueries';
export * from './pointQueries'; export * from './pointQueries';
export * from './postQueries'; export * from './postQueries';
export * from './walletQueries'; export * from './walletQueries';
export * from './leaderboardQueries'; export * from './leaderboardQueries';

View File

@ -122,7 +122,7 @@ export const useDiscussionQuery = (_author?: string, _permlink?: string) => {
); );
useEffect(() => { useEffect(() => {
const _data = injectPostCache(query.data, cachedComments, cachedVotes, lastCacheUpdate); const _data = injectPostCache(query.data, cachedComments, cachedVotes, lastCacheUpdate);
setData(_data); setData(_data);
}, [query.data, cachedComments, cachedVotes]); }, [query.data, cachedComments, cachedVotes]);
@ -130,7 +130,6 @@ export const useDiscussionQuery = (_author?: string, _permlink?: string) => {
restructureData(); restructureData();
}, [data]); }, [data]);
// traverse discussion collection to curate sections // traverse discussion collection to curate sections
const restructureData = async () => { const restructureData = async () => {
const MAX_THREAD_LEVEL = 3; const MAX_THREAD_LEVEL = 3;

View File

@ -1,33 +1,27 @@
import { UseMutationOptions, useMutation, useQueries, useQueryClient } from '@tanstack/react-query';
import {
UseMutationOptions,
useMutation,
useQueries, useQueryClient,
} from '@tanstack/react-query';
import { useEffect, useMemo, useRef, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
import { unionBy, isArray } from 'lodash'; import { unionBy, isArray } from 'lodash';
import { getDiscussionCollection } from '../../hive/dhive'; import { getDiscussionCollection, getAccountPosts } from '../../hive/dhive';
import { getAccountPosts } from '../../hive/dhive';
import QUERIES from '../queryKeys'; import QUERIES from '../queryKeys';
import { delay } from '../../../utils/editor'; import { delay } from '../../../utils/editor';
import { injectPostCache, injectVoteCache, mapDiscussionToThreads } from '../../../utils/postParser'; import {
injectPostCache,
injectVoteCache,
mapDiscussionToThreads,
} from '../../../utils/postParser';
import { useAppSelector } from '../../../hooks'; import { useAppSelector } from '../../../hooks';
export const useWavesQuery = (host: string) => { export const useWavesQuery = (host: string) => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const cache = useAppSelector(state => state.cache); const cache = useAppSelector((state) => state.cache);
const mutes = useAppSelector(state => state.account.currentAccount.mutes); const mutes = useAppSelector((state) => state.account.currentAccount.mutes);
const cacheRef = useRef(cache); const cacheRef = useRef(cache);
const cachedVotes = cache.votesCollection const cachedVotes = cache.votesCollection;
const lastCacheUpdate = cache.lastUpdate const lastCacheUpdate = cache.lastUpdate;
const [isRefreshing, setIsRefreshing] = useState(false); const [isRefreshing, setIsRefreshing] = useState(false);
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
@ -35,102 +29,99 @@ export const useWavesQuery = (host: string) => {
const wavesIndexCollection = useRef<{ [key: string]: string }>({}); const wavesIndexCollection = useRef<{ [key: string]: string }>({});
const _initialContainerPermlinks = useMemo(() => const _initialContainerPermlinks = useMemo(
queryClient.getQueryData<string[]>([QUERIES.WAVES.INITIAL_CONTAINERS, host]) || [], []); () => queryClient.getQueryData<string[]>([QUERIES.WAVES.INITIAL_CONTAINERS, host]) || [],
[],
);
const [permlinksBucket, setPermlinksBucket] = useState<string[]>(_initialContainerPermlinks); const [permlinksBucket, setPermlinksBucket] = useState<string[]>(_initialContainerPermlinks);
// query initialization // query initialization
const wavesQueries = useQueries({ const wavesQueries = useQueries({
queries: activePermlinks.map((pagePermlink, index) => ({ queries: activePermlinks.map((pagePermlink, index) => ({
queryKey: [QUERIES.WAVES.GET, host, pagePermlink, index], //index at end is used to track query hydration queryKey: [QUERIES.WAVES.GET, host, pagePermlink, index], // index at end is used to track query hydration
queryFn: () => _fetchWaves(pagePermlink), queryFn: () => _fetchWaves(pagePermlink),
initialData: [], initialData: [],
})), })),
}); });
// hook to update cache reference,
//hook to update cache reference, // workaround required since query fucntion do get passed an
//workaround required since query fucntion do get passed an // updated copy for states that are not part of query key and contexet while conext is not
//updated copy for states that are not part of query key and contexet while conext is not // supported by useQueries
//supported by useQueries
useEffect(() => { useEffect(() => {
cacheRef.current = cache; cacheRef.current = cache;
}, [cache]) }, [cache]);
useEffect(() => { useEffect(() => {
_fetchPermlinks('', true); _fetchPermlinks('', true);
}, []) }, []);
useEffect(() => { useEffect(() => {
if (!!permlinksBucket.length) { if (permlinksBucket.length) {
//if first elements permlinks do not match, means there is a new container, push at first // if first elements permlinks do not match, means there is a new container, push at first
if (permlinksBucket[0] !== activePermlinks[0]) { if (permlinksBucket[0] !== activePermlinks[0]) {
activePermlinks.splice(0, 0, permlinksBucket[0]); activePermlinks.splice(0, 0, permlinksBucket[0]);
} }
//permlinks bucket is updated, it needs to be connect with active one to start chain again // permlinks bucket is updated, it needs to be connect with active one to start chain again
else { else {
activePermlinks.push(permlinksBucket[activePermlinks.length]); activePermlinks.push(permlinksBucket[activePermlinks.length]);
} }
setActivePermlinks([...activePermlinks]); setActivePermlinks([...activePermlinks]);
} }
}, [permlinksBucket]) }, [permlinksBucket]);
useEffect(() => { useEffect(() => {
const _latestData = wavesQueries.lastItem?.data; const _latestData = wavesQueries.lastItem?.data;
if (!_latestData || _latestData.length < 10) { if (!_latestData || _latestData.length < 10) {
_fetchNextPage(); _fetchNextPage();
} }
}, [wavesQueries.lastItem?.data]) }, [wavesQueries.lastItem?.data]);
useEffect(() => { useEffect(() => {
//check cache is recently updated and take post path // check cache is recently updated and take post path
if (lastCacheUpdate) { if (lastCacheUpdate) {
const _timeElapsed = new Date().getTime() - lastCacheUpdate.updatedAt const _timeElapsed = new Date().getTime() - lastCacheUpdate.updatedAt;
if (lastCacheUpdate.type === 'vote' && _timeElapsed < 5000) { if (lastCacheUpdate.type === 'vote' && _timeElapsed < 5000) {
_injectPostCache(lastCacheUpdate.postPath) _injectPostCache(lastCacheUpdate.postPath);
} }
} }
}, [lastCacheUpdate]);
}, [lastCacheUpdate])
const _injectPostCache = async (postPath: string) => { const _injectPostCache = async (postPath: string) => {
//using post path get index of query key where that post exists // using post path get index of query key where that post exists
const _containerPermlink = wavesIndexCollection.current[postPath]; const _containerPermlink = wavesIndexCollection.current[postPath];
const _containerIndex = activePermlinks.indexOf(_containerPermlink) const _containerIndex = activePermlinks.indexOf(_containerPermlink);
const _voteCache = cachedVotes[postPath]; const _voteCache = cachedVotes[postPath];
if (_containerIndex >= 0 && _voteCache) { if (_containerIndex >= 0 && _voteCache) {
//mean data exist, get query data, update query data by finding post and injecting cache // mean data exist, get query data, update query data by finding post and injecting cache
const _qData: any[] | undefined = wavesQueries[_containerIndex].data; const _qData: any[] | undefined = wavesQueries[_containerIndex].data;
if (_qData) { if (_qData) {
const _postIndex = _qData.findIndex((item) => lastCacheUpdate.postPath === `${item.author}/${item.permlink}`); const _postIndex = _qData.findIndex(
(item) => lastCacheUpdate.postPath === `${item.author}/${item.permlink}`,
);
const _post = _qData[_postIndex]; const _post = _qData[_postIndex];
if (_post) { if (_post) {
//inject cache and set query data // inject cache and set query data
const _cPost = injectVoteCache(_post, _voteCache); const _cPost = injectVoteCache(_post, _voteCache);
_qData.splice(_postIndex, 1, _cPost); _qData.splice(_postIndex, 1, _cPost);
queryClient.setQueryData([QUERIES.WAVES.GET, host, _containerPermlink, _containerIndex], [..._qData]); //TODO: use container permlink as well queryClient.setQueryData(
[QUERIES.WAVES.GET, host, _containerPermlink, _containerIndex],
[..._qData],
); // TODO: use container permlink as well
} }
} }
} }
} };
const _fetchPermlinks = async (startPermlink = '', refresh = false) => { const _fetchPermlinks = async (startPermlink = '', refresh = false) => {
setIsLoading(true); setIsLoading(true);
try { try {
const query: any = { const query: any = {
account: host, account: host,
start_author: !!startPermlink ? host : '', start_author: startPermlink ? host : '',
start_permlink: startPermlink, start_permlink: startPermlink,
limit: 5, limit: 5,
observer: '', observer: '',
@ -139,56 +130,53 @@ export const useWavesQuery = (host: string) => {
const result = await getAccountPosts(query); const result = await getAccountPosts(query);
const _fetchedPermlinks = result.map(post => post.permlink); const _fetchedPermlinks = result.map((post) => post.permlink);
console.log('permlinks fetched', _fetchedPermlinks); console.log('permlinks fetched', _fetchedPermlinks);
const _permlinksBucket = refresh ? _fetchedPermlinks : [...permlinksBucket, ..._fetchedPermlinks]; const _permlinksBucket = refresh
? _fetchedPermlinks
: [...permlinksBucket, ..._fetchedPermlinks];
setPermlinksBucket(_permlinksBucket); setPermlinksBucket(_permlinksBucket);
if (refresh) { if (refresh) {
queryClient.setQueryData([QUERIES.WAVES.INITIAL_CONTAINERS, host], _permlinksBucket); queryClient.setQueryData([QUERIES.WAVES.INITIAL_CONTAINERS, host], _permlinksBucket);
//precautionary delay of 200ms to let state update before concluding promise, // precautionary delay of 200ms to let state update before concluding promise,
//it is effective for waves refresh routine. // it is effective for waves refresh routine.
await delay(200) await delay(200);
} }
} catch (err) { } catch (err) {
console.warn("failed to fetch waves permlinks"); console.warn('failed to fetch waves permlinks');
} }
setIsLoading(false) setIsLoading(false);
};
}
const _fetchWaves = async (pagePermlink: string) => { const _fetchWaves = async (pagePermlink: string) => {
console.log('fetching waves from:', host, pagePermlink); console.log('fetching waves from:', host, pagePermlink);
const response = await getDiscussionCollection(host, pagePermlink); const response = await getDiscussionCollection(host, pagePermlink);
//inject cache here... // inject cache here...
const _cachedComments = cacheRef.current.commentsCollection; const _cachedComments = cacheRef.current.commentsCollection;
const _cachedVotes = cacheRef.current.votesCollection; const _cachedVotes = cacheRef.current.votesCollection;
const _lastCacheUpdate = cacheRef.current.lastCacheUpdate const _lastCacheUpdate = cacheRef.current.lastCacheUpdate;
const _cResponse = injectPostCache(response, _cachedComments, _cachedVotes, _lastCacheUpdate); const _cResponse = injectPostCache(response, _cachedComments, _cachedVotes, _lastCacheUpdate);
const _threadedComments = await mapDiscussionToThreads(_cResponse, host, pagePermlink, 1); const _threadedComments = await mapDiscussionToThreads(_cResponse, host, pagePermlink, 1);
if (!_threadedComments) { if (!_threadedComments) {
throw new Error("Failed to parse waves"); throw new Error('Failed to parse waves');
} }
_threadedComments.sort((a, b) => new Date(a.created) > new Date(b.created) ? -1 : 1); _threadedComments.sort((a, b) => (new Date(a.created) > new Date(b.created) ? -1 : 1));
_threadedComments.forEach((item) => { _threadedComments.forEach((item) => {
wavesIndexCollection.current[`${item.author}/${item.permlink}`] = pagePermlink wavesIndexCollection.current[`${item.author}/${item.permlink}`] = pagePermlink;
}) });
console.log('new waves fetched', _threadedComments); console.log('new waves fetched', _threadedComments);
return _threadedComments || []; return _threadedComments || [];
}; };
const _fetchNextPage = () => { const _fetchNextPage = () => {
const lastPage = wavesQueries.lastItem; const lastPage = wavesQueries.lastItem;
@ -199,17 +187,15 @@ export const useWavesQuery = (host: string) => {
const _nextPagePermlink = permlinksBucket[activePermlinks.length]; const _nextPagePermlink = permlinksBucket[activePermlinks.length];
if (_nextPagePermlink && !activePermlinks.includes(_nextPagePermlink)) { if (_nextPagePermlink && !activePermlinks.includes(_nextPagePermlink)) {
console.log("updating next page permlink", _nextPagePermlink) console.log('updating next page permlink', _nextPagePermlink);
activePermlinks.push(_nextPagePermlink); activePermlinks.push(_nextPagePermlink);
setActivePermlinks([...activePermlinks]); setActivePermlinks([...activePermlinks]);
} else { } else {
console.log("fetching new containers", permlinksBucket.lastItem) console.log('fetching new containers', permlinksBucket.lastItem);
_fetchPermlinks(permlinksBucket.lastItem) _fetchPermlinks(permlinksBucket.lastItem);
} }
}; };
const _refresh = async () => { const _refresh = async () => {
setIsRefreshing(true); setIsRefreshing(true);
setPermlinksBucket([]); setPermlinksBucket([]);
@ -219,38 +205,32 @@ export const useWavesQuery = (host: string) => {
setIsRefreshing(false); setIsRefreshing(false);
}; };
const _data = unionBy(...wavesQueries.map((query) => query.data), 'url'); const _data = unionBy(...wavesQueries.map((query) => query.data), 'url');
const _filteredData = useMemo(() => const _filteredData = useMemo(
_data.filter(post => isArray(mutes) ? mutes.indexOf(post?.author) < 0 : true), () => _data.filter((post) => (isArray(mutes) ? mutes.indexOf(post?.author) < 0 : true)),
[mutes, _data]) [mutes, _data],
);
const _lastestWavesFetch = async () => { const _lastestWavesFetch = async () => {
await _fetchPermlinks('', true); await _fetchPermlinks('', true);
const _prevLatestWave = _filteredData[0] const _prevLatestWave = _filteredData[0];
const _firstQuery = wavesQueries[0]; const _firstQuery = wavesQueries[0];
if(!_firstQuery){ if (!_firstQuery) {
return []; return [];
} }
const queryResponse = await _firstQuery.refetch(); const queryResponse = await _firstQuery.refetch();
const _newData:any[] = queryResponse.data || []; const _newData: any[] = queryResponse.data || [];
//check if new waves are available // check if new waves are available
const _lastIndex = _newData?.findIndex(item => const _lastIndex = _newData?.findIndex(
( item.author + item.permlink === _prevLatestWave.author + _prevLatestWave.permlink)); (item) => item.author + item.permlink === _prevLatestWave.author + _prevLatestWave.permlink,
);
let _newWaves:any[] = [] let _newWaves: any[] = [];
if (_lastIndex && _lastIndex !== 0) { if (_lastIndex && _lastIndex !== 0) {
if (_lastIndex < 0) { if (_lastIndex < 0) {
_newWaves = _newData?.slice(0, 5) || []; _newWaves = _newData?.slice(0, 5) || [];
@ -259,10 +239,8 @@ export const useWavesQuery = (host: string) => {
} }
} }
return _newWaves;
return _newWaves };
}
return { return {
data: _filteredData, data: _filteredData,
@ -274,26 +252,21 @@ export const useWavesQuery = (host: string) => {
}; };
}; };
export const usePublishWaveMutation = () => { export const usePublishWaveMutation = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
// id is options, if no id is provided program marks all notifications as read; // id is options, if no id is provided program marks all notifications as read;
const _mutationFn = async (cachePostData: any) => { const _mutationFn = async (cachePostData: any) => {
//TODO: lates port wave publishing here or introduce post publishing mutation; // TODO: lates port wave publishing here or introduce post publishing mutation;
if (cachePostData) { //TODO: expand to check multiple wave hosts;{ if (cachePostData) {
// TODO: expand to check multiple wave hosts;{
const _host = cachePostData.parent_author; const _host = cachePostData.parent_author;
console.log('returning waves host', _host); console.log('returning waves host', _host);
return _host; return _host;
} }
throw new Error("invalid mutations data") throw new Error('invalid mutations data');
}; };
const _options: UseMutationOptions<string, unknown, any, void> = { const _options: UseMutationOptions<string, unknown, any, void> = {
@ -314,11 +287,10 @@ export const usePublishWaveMutation = () => {
queryData.splice(0, 0, cacheCommentData); queryData.splice(0, 0, cacheCommentData);
queryClient.setQueryData(_queryKey, queryData); queryClient.setQueryData(_queryKey, queryData);
} }
}, },
onSuccess: async (host) => { onSuccess: async (host) => {
//TODO: get first container permlink here from initial containers // TODO: get first container permlink here from initial containers
const queriesData = queryClient.getQueriesData([QUERIES.WAVES.INITIAL_CONTAINERS, host]); const queriesData = queryClient.getQueriesData([QUERIES.WAVES.INITIAL_CONTAINERS, host]);
const _queryKey = queriesData[0][0]; const _queryKey = queriesData[0][0];
queryClient.invalidateQueries(_queryKey); queryClient.invalidateQueries(_queryKey);
@ -328,8 +300,6 @@ export const usePublishWaveMutation = () => {
return useMutation(_mutationFn, _options); return useMutation(_mutationFn, _options);
}; };
export const fetchLatestWavesContainer = async (host) => { export const fetchLatestWavesContainer = async (host) => {
const query: any = { const query: any = {
account: host, account: host,
@ -346,8 +316,8 @@ export const fetchLatestWavesContainer = async (host) => {
console.log('lates waves post', host, _latestPost); console.log('lates waves post', host, _latestPost);
if (!_latestPost) { if (!_latestPost) {
throw new Error("Lates waves container could be not fetched"); throw new Error('Lates waves container could be not fetched');
} }
return _latestPost; return _latestPost;
} };

View File

@ -30,8 +30,8 @@ const QUERIES = {
}, },
WAVES: { WAVES: {
GET: 'QUERY_GET_WAVES', GET: 'QUERY_GET_WAVES',
INITIAL_CONTAINERS: 'QUERY_DATA_INITIAL_CONTAINERS' INITIAL_CONTAINERS: 'QUERY_DATA_INITIAL_CONTAINERS',
} },
}; };
export default QUERIES; export default QUERIES;

View File

@ -99,10 +99,10 @@ export const setLockedOrientation = (payload: string) => ({
type: SET_LOCKED_ORIENTATION, type: SET_LOCKED_ORIENTATION,
}); });
export const showReplyModal = ({mode, parentPost}:PostEditorModalData) => ({ export const showReplyModal = ({ mode, parentPost }: PostEditorModalData) => ({
payload: { payload: {
mode: mode || 'comment', mode: mode || 'comment',
parentPost parentPost,
} as PostEditorModalData, } as PostEditorModalData,
type: SHOW_REPLY_MODAL, type: SHOW_REPLY_MODAL,
}); });

View File

@ -63,7 +63,7 @@ export const fetchCoinQuotes = () => (dispatch, getState) => {
}; };
export const fetchAndSetCoinsData = export const fetchAndSetCoinsData =
(refresh: boolean = false) => (refresh = false) =>
async (dispatch: AppDispatch, getState: RootState) => { async (dispatch: AppDispatch, getState: RootState) => {
const coins = getState().wallet.selectedCoins; const coins = getState().wallet.selectedCoins;
const { quotes } = getState().wallet; const { quotes } = getState().wallet;

View File

@ -20,10 +20,9 @@ import {
} from '../constants/constants'; } from '../constants/constants';
import { orientations } from '../constants/orientationsConstants'; import { orientations } from '../constants/orientationsConstants';
export interface PostEditorModalData { export interface PostEditorModalData {
mode:'wave'|'comment'|'post', mode: 'wave' | 'comment' | 'post';
parentPost?:any parentPost?: any;
} }
interface UiState { interface UiState {
@ -153,8 +152,8 @@ export default function (state = initialState, action): UiState {
}; };
case SHOW_REPLY_MODAL: case SHOW_REPLY_MODAL:
const _payload = action.payload as PostEditorModalData; const _payload = action.payload as PostEditorModalData;
if(_payload.mode === 'comment' && !_payload.parentPost){ if (_payload.mode === 'comment' && !_payload.parentPost) {
throw new Error("parent post missing for showing post editor modal with comment mode") throw new Error('parent post missing for showing post editor modal with comment mode');
} }
return { return {
...state, ...state,

View File

@ -2,12 +2,12 @@ import React, { ComponentType, JSXElementConstructor, ReactElement, useState } f
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { SectionList, Text, RefreshControl, ActivityIndicator } from 'react-native'; import { SectionList, Text, RefreshControl, ActivityIndicator } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet'; import EStyleSheet from 'react-native-extended-stylesheet';
import { useQueryClient } from '@tanstack/react-query';
import { Transaction } from '../../../components'; import { Transaction } from '../../../components';
import { useAppSelector } from '../../../hooks'; import { useAppSelector } from '../../../hooks';
import { CoinActivity } from '../../../redux/reducers/walletReducer'; import { CoinActivity } from '../../../redux/reducers/walletReducer';
import styles from './children.styles'; import styles from './children.styles';
import { limitOrderCancel } from '../../../providers/hive-trade/hiveTrade'; import { limitOrderCancel } from '../../../providers/hive-trade/hiveTrade';
import { useQueryClient } from '@tanstack/react-query';
import QUERIES from '../../../providers/queries/queryKeys'; import QUERIES from '../../../providers/queries/queryKeys';
import TransferTypes from '../../../constants/transferTypes'; import TransferTypes from '../../../constants/transferTypes';

View File

@ -9,8 +9,8 @@ export default EStyleSheet.create({
overflow: 'hidden', overflow: 'hidden',
backgroundColor: '$primaryLightBackground', backgroundColor: '$primaryLightBackground',
} as ViewStyle, } as ViewStyle,
iconContainer:{ iconContainer: {
marginRight:8 marginRight: 8,
} as ViewStyle, } as ViewStyle,
basicsContainer: { basicsContainer: {
alignItems: 'center', alignItems: 'center',
@ -18,8 +18,8 @@ export default EStyleSheet.create({
} as ViewStyle, } as ViewStyle,
coinTitleContainer: { coinTitleContainer: {
flexDirection: 'row', flexDirection: 'row',
alignItems:'center', alignItems: 'center',
marginTop:8 marginTop: 8,
} as ViewStyle, } as ViewStyle,
textCoinTitle: { textCoinTitle: {
color: '$primaryBlack', color: '$primaryBlack',
@ -98,10 +98,8 @@ export default EStyleSheet.create({
paddingHorizontal: 16, paddingHorizontal: 16,
} as ViewStyle, } as ViewStyle,
//COIN ACTIONS STYLES // COIN ACTIONS STYLES
actionBtnContainer: { actionBtnContainer: {} as ViewStyle,
} as ViewStyle,
actionsContainer: { actionsContainer: {
flexDirection: 'row', flexDirection: 'row',
flexWrap: 'wrap', flexWrap: 'wrap',

View File

@ -66,12 +66,9 @@ export const CoinBasics = ({
}; };
const _renderExtraData = (args: DataPair, index: number) => { const _renderExtraData = (args: DataPair, index: number) => {
const label = intl.formatMessage( const label = intl.formatMessage(
{ id: `wallet.${args.dataKey || args.labelId}` }, { id: `wallet.${args.dataKey || args.labelId}` },
args.subValue args.subValue ? { subValue: args.subValue } : undefined,
? { subValue: args.subValue }
: undefined
); );
const _onPress = () => { const _onPress = () => {

View File

@ -31,11 +31,7 @@ export const CoinChart = ({ coinId, isEngine }: CoinChartProps) => {
); );
setChartData(marketData.map((item) => item.close)); setChartData(marketData.map((item) => item.close));
} else { } else {
const marketData = await fetchMarketChart( const marketData = await fetchMarketChart(coinId, currency.currency, days);
coinId,
currency.currency,
days
);
setChartData(marketData.prices.map((item) => item.yValue)); setChartData(marketData.prices.map((item) => item.yValue));
} }
}; };

View File

@ -27,7 +27,7 @@ export const CoinSummary = ({
const valuePairs = [ const valuePairs = [
{ {
dataKey: 'amount_desc', dataKey: 'amount_desc',
value: balance.toFixed(precision ? precision : 3), value: balance.toFixed(precision || 3),
}, },
] as DataPair[]; ] as DataPair[];

View File

@ -52,9 +52,9 @@ export const DelegationsModal = forwardRef(({}, ref) => {
} }
}, [mode, showModal]); }, [mode, showModal]);
const _getVestingDelegations = async (startUsername: string = '') => { const _getVestingDelegations = async (startUsername = '') => {
let resData: any = []; let resData: any = [];
let limit = 1000; const limit = 1000;
const response = await getVestingDelegations(currentAccount.username, startUsername, limit); const response = await getVestingDelegations(currentAccount.username, startUsername, limit);
resData = response.map( resData = response.map(
@ -132,7 +132,7 @@ export const DelegationsModal = forwardRef(({}, ref) => {
const title = intl.formatMessage({ id: `wallet.${mode}` }); const title = intl.formatMessage({ id: `wallet.${mode}` });
const _renderItem = ({ item, index }: { item: DelegationItem; index: number }) => { const _renderItem = ({ item, index }: { item: DelegationItem; index: number }) => {
const value = vestsToHp(item.vestingShares, globalProps.hivePerMVests).toFixed(3) + ' HP'; const value = `${vestsToHp(item.vestingShares, globalProps.hivePerMVests).toFixed(3)} HP`;
const timeString = new Date(item.timestamp).toDateString(); const timeString = new Date(item.timestamp).toDateString();
const subRightText = const subRightText =
mode === MODES.DELEGATEED && intl.formatMessage({ id: 'wallet.tap_update' }); mode === MODES.DELEGATEED && intl.formatMessage({ id: 'wallet.tap_update' });

View File

@ -15,33 +15,34 @@ interface RangeSelectorProps {
} }
export const RangeSelector = ({ range, minRange, onRangeChange }: RangeSelectorProps) => { export const RangeSelector = ({ range, minRange, onRangeChange }: RangeSelectorProps) => {
const _onSelection = (range: number) => { const _onSelection = (range: number) => {
console.log('selection', range); console.log('selection', range);
onRangeChange(range); onRangeChange(range);
}; };
const _renderRangeButtons = FILTERS.filter((item) => item.value >= minRange).map((item: RangeOption) => ( const _renderRangeButtons = FILTERS.filter((item) => item.value >= minRange).map(
<TouchableOpacity key={`range option-${item.value}`} onPress={() => _onSelection(item.value)}> (item: RangeOption) => (
<View <TouchableOpacity key={`range option-${item.value}`} onPress={() => _onSelection(item.value)}>
style={{ <View
...styles.rangeOptionWrapper,
backgroundColor: EStyleSheet.value(
item.value === range ? '$darkGrayBackground' : '$primaryLightBackground',
),
}}
>
<Text
style={{ style={{
...styles.textRange, ...styles.rangeOptionWrapper,
color: EStyleSheet.value(item.value === range ? '$white' : '$primaryDarkText'), backgroundColor: EStyleSheet.value(
item.value === range ? '$darkGrayBackground' : '$primaryLightBackground',
),
}} }}
> >
{item.label} <Text
</Text> style={{
</View> ...styles.textRange,
</TouchableOpacity> color: EStyleSheet.value(item.value === range ? '$white' : '$primaryDarkText'),
)); }}
>
{item.label}
</Text>
</View>
</TouchableOpacity>
),
);
return <View style={[styles.card, styles.rangeContainer]}>{_renderRangeButtons}</View>; return <View style={[styles.card, styles.rangeContainer]}>{_renderRangeButtons}</View>;
}; };

View File

@ -3,7 +3,7 @@ import EStyleSheet from 'react-native-extended-stylesheet';
import getWindowDimensions from '../../../utils/getWindowDimensions'; import getWindowDimensions from '../../../utils/getWindowDimensions';
export default EStyleSheet.create({ export default EStyleSheet.create({
modalStyle:{ modalStyle: {
flex: 1, flex: 1,
backgroundColor: '$primaryBackgroundColor', backgroundColor: '$primaryBackgroundColor',
margin: 0, margin: 0,
@ -23,7 +23,7 @@ export default EStyleSheet.create({
} as ViewStyle, } as ViewStyle,
scrollContainer: { scrollContainer: {
flex:1, flex: 1,
marginTop: 16, marginTop: 16,
marginBottom: 16, marginBottom: 16,
} as ViewStyle, } as ViewStyle,
@ -35,33 +35,30 @@ export default EStyleSheet.create({
} as TextStyle, } as TextStyle,
modalContainer: { modalContainer: {
flex:1, flex: 1,
marginBottom: 44, marginBottom: 44,
paddingHorizontal: 24, paddingHorizontal: 24,
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
} as ViewStyle, } as ViewStyle,
sectionTextStyle : { sectionTextStyle: {
color:'$primaryBlack', color: '$primaryBlack',
fontSize: 16, fontSize: 16,
marginHorizontal: 16, marginHorizontal: 16,
marginVertical:4, marginVertical: 4,
} as TextStyle, } as TextStyle,
sectionSubTextStyle : { sectionSubTextStyle: {
color:'$iconColor', color: '$iconColor',
fontSize: 18, fontSize: 18,
marginHorizontal: 16, marginHorizontal: 16,
marginVertical:16, marginVertical: 16,
alignSelf:'center' alignSelf: 'center',
} as TextStyle, } as TextStyle,
dragBtnContainer:{ dragBtnContainer: {
padding:8 padding: 8,
} as ViewStyle, } as ViewStyle,
title: { title: {
@ -83,12 +80,12 @@ export default EStyleSheet.create({
btnText: { btnText: {
color: '$pureWhite', color: '$pureWhite',
textTransform: 'uppercase' textTransform: 'uppercase',
} as TextStyle, } as TextStyle,
assetIconContainer:{ assetIconContainer: {
width:32, width: 32,
marginLeft:16 marginLeft: 16,
}, },
button: { button: {

View File

@ -2,6 +2,7 @@ import React, { Fragment, useState, useEffect, useRef } from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { ScrollView, Text, TouchableOpacity, View } from 'react-native'; import { ScrollView, Text, TouchableOpacity, View } from 'react-native';
import { gestureHandlerRootHOC } from 'react-native-gesture-handler'; import { gestureHandlerRootHOC } from 'react-native-gesture-handler';
import get from 'lodash/get';
import { BasicHeader, TextBoxWithCopy } from '../../components'; import { BasicHeader, TextBoxWithCopy } from '../../components';
import { useAppSelector } from '../../hooks'; import { useAppSelector } from '../../hooks';
import { getDigitPinCode } from '../../providers/hive/dhive'; import { getDigitPinCode } from '../../providers/hive/dhive';
@ -13,7 +14,6 @@ import styles from './backupKeysScreenStyles';
// utils // utils
import { decryptKey } from '../../utils/crypto'; import { decryptKey } from '../../utils/crypto';
import get from 'lodash/get';
const BackupKeysScreen = () => { const BackupKeysScreen = () => {
const intl = useIntl(); const intl = useIntl();

View File

@ -1,13 +1,13 @@
import { View, Text, TouchableOpacity, Alert } from 'react-native'; import { View, Text, TouchableOpacity, Alert } from 'react-native';
import React, { forwardRef, useImperativeHandle, useState } from 'react'; import React, { forwardRef, useImperativeHandle, useState } from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import { useDispatch } from 'react-redux';
import EStyleSheet from 'react-native-extended-stylesheet';
import { Modal, TextInput } from '../../components'; import { Modal, TextInput } from '../../components';
import { useAppSelector } from '../../hooks'; import { useAppSelector } from '../../hooks';
import { useDispatch } from 'react-redux';
// styles // styles
import styles from './backupKeysScreenStyles'; import styles from './backupKeysScreenStyles';
import EStyleSheet from 'react-native-extended-stylesheet';
// redux / providers // redux / providers
import { getUpdatedUserKeys } from '../../providers/hive/auth'; import { getUpdatedUserKeys } from '../../providers/hive/auth';

View File

@ -5,7 +5,7 @@ export default EStyleSheet.create({
userRibbonContainer: { userRibbonContainer: {
borderBottomWidth: EStyleSheet.hairlineWidth, borderBottomWidth: EStyleSheet.hairlineWidth,
borderColor: '$darkGrayBackground', borderColor: '$darkGrayBackground',
marginBottom: 0, //without 0 margin, view will start overlapping UserRibbon marginBottom: 0, // without 0 margin, view will start overlapping UserRibbon
paddingBottom: 32, paddingBottom: 32,
} as ViewStyle, } as ViewStyle,

View File

@ -78,7 +78,7 @@ const DraftsContainer = ({ currentAccount, navigation, route }) => {
const _isCloning = isCloningDraft; const _isCloning = isCloningDraft;
const _getUpdatedArray = (arr: string[], id: string) => { const _getUpdatedArray = (arr: string[], id: string) => {
let _tempArr = arr.slice(); const _tempArr = arr.slice();
const index = _tempArr.findIndex((item) => item === id); const index = _tempArr.findIndex((item) => item === id);
if (index !== -1) { if (index !== -1) {

View File

@ -2,12 +2,12 @@ import React, { useState, useRef, useEffect, useMemo } from 'react';
import { View } from 'react-native'; import { View } from 'react-native';
// Components // Components
import FastImage from 'react-native-fast-image';
import { BasicHeader, IconButton, PostDisplay, PostOptionsModal } from '../../../components'; import { BasicHeader, IconButton, PostDisplay, PostOptionsModal } from '../../../components';
import styles from '../styles/postScreen.styles'; import styles from '../styles/postScreen.styles';
// Component // Component
import { postQueries } from '../../../providers/queries'; import { postQueries } from '../../../providers/queries';
import FastImage from 'react-native-fast-image';
const PostScreen = ({ route }) => { const PostScreen = ({ route }) => {
const params = route.params || {}; const params = route.params || {};
@ -22,21 +22,23 @@ const PostScreen = ({ route }) => {
const getPostQuery = postQueries.useGetPostQuery(author, permlink, params.content); const getPostQuery = postQueries.useGetPostQuery(author, permlink, params.content);
const getParentPostQuery = postQueries.useGetPostQuery(); const getParentPostQuery = postQueries.useGetPostQuery();
const isWavePost = useMemo(() => getPostQuery.data?.parent_author === 'ecency.waves', [getPostQuery.data]) //TODO: implement a better generic way to avoid parent fetching for waves const isWavePost = useMemo(
() => getPostQuery.data?.parent_author === 'ecency.waves',
[getPostQuery.data],
); // TODO: implement a better generic way to avoid parent fetching for waves
useEffect(() => { useEffect(() => {
return () => { return () => {
//clears FastImage RAM, not disk usage; // clears FastImage RAM, not disk usage;
FastImage.clearMemoryCache(); FastImage.clearMemoryCache();
} };
}, []) }, []);
useEffect(() => { useEffect(() => {
const post = getPostQuery.data; const post = getPostQuery.data;
if (post) { if (post) {
const _fetchParent = post && post.depth > 0 const _fetchParent =
&& post.parent_author && post.parent_permlink post && post.depth > 0 && post.parent_author && post.parent_permlink && !isWavePost;
&& !isWavePost;
if (_fetchParent) { if (_fetchParent) {
getParentPostQuery.setAuthor(post.parent_author); getParentPostQuery.setAuthor(post.parent_author);

View File

@ -313,29 +313,33 @@ class SettingsContainer extends Component {
navigateTo: ROUTES.SCREENS.BACKUP_KEYS, navigateTo: ROUTES.SCREENS.BACKUP_KEYS,
}); });
} else { } else {
dispatch(showActionModal({ dispatch(
title:intl.formatMessage({id:'alert.warning'}), showActionModal({
body:intl.formatMessage({id:'settings.keys_warning'}), title: intl.formatMessage({ id: 'alert.warning' }),
buttons:[{ body: intl.formatMessage({ id: 'settings.keys_warning' }),
text:intl.formatMessage({id:'alert.cancel'}), buttons: [
onPress:()=>{}, {
type:'destructive' text: intl.formatMessage({ id: 'alert.cancel' }),
},{ onPress: () => {},
text:intl.formatMessage({id:'settings.set_pin'}), type: 'destructive',
onPress:()=>{ },
navigation.navigate(ROUTES.SCREENS.PINCODE, { {
callback: () => { text: intl.formatMessage({ id: 'settings.set_pin' }),
this._enableDefaultUnlockPin(true) onPress: () => {
navigation.navigate(ROUTES.SCREENS.PINCODE, {
callback: () => {
this._enableDefaultUnlockPin(true);
},
navigateTo: ROUTES.SCREENS.BACKUP_KEYS,
isReset: true,
isOldPinVerified: true,
oldPinCode: Config.DEFAULT_PIN,
});
}, },
navigateTo: ROUTES.SCREENS.BACKUP_KEYS, },
isReset: true, ],
isOldPinVerified: true, }),
oldPinCode: Config.DEFAULT_PIN, );
});
}
}]
}))
} }
break; break;

View File

@ -32,7 +32,6 @@ export const SwapTokenContent = ({ initialSymbol, handleHsTransfer, onSuccess }:
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const navigation = useNavigation(); const navigation = useNavigation();
const currentAccount = useAppSelector((state) => state.account.currentAccount); const currentAccount = useAppSelector((state) => state.account.currentAccount);
const currency = useAppSelector((state) => state.application.currency); const currency = useAppSelector((state) => state.application.currency);
@ -56,12 +55,10 @@ export const SwapTokenContent = ({ initialSymbol, handleHsTransfer, onSuccess }:
const _fromAssetId = fromAssetSymbol === MarketAsset.HBD ? ASSET_IDS.HBD : ASSET_IDS.HIVE; const _fromAssetId = fromAssetSymbol === MarketAsset.HBD ? ASSET_IDS.HBD : ASSET_IDS.HIVE;
const _toAssetId = _toAssetSymbol === MarketAsset.HBD ? ASSET_IDS.HBD : ASSET_IDS.HIVE; const _toAssetId = _toAssetSymbol === MarketAsset.HBD ? ASSET_IDS.HBD : ASSET_IDS.HIVE;
// queres // queres
const assetsQuery = walletQueries.useAssetsQuery(); const assetsQuery = walletQueries.useAssetsQuery();
const pendingRequestsQuery = walletQueries.usePendingRequestsQuery(_fromAssetId); const pendingRequestsQuery = walletQueries.usePendingRequestsQuery(_fromAssetId);
// this method makes sure amount is only updated when new order book is fetched after asset change // this method makes sure amount is only updated when new order book is fetched after asset change
// this avoid wrong from and to swap value on changing source asset // this avoid wrong from and to swap value on changing source asset
const _onAssetChangeComplete = () => { const _onAssetChangeComplete = () => {
@ -93,8 +90,7 @@ export const SwapTokenContent = ({ initialSymbol, handleHsTransfer, onSuccess }:
const _fromAssetData = assetsData[_fromAssetId]; const _fromAssetData = assetsData[_fromAssetId];
const _balance = _fromAssetData.balance; const _balance = _fromAssetData.balance;
const _fromFiatPrice = _fromAssetData.currentPrice; const _fromFiatPrice = _fromAssetData.currentPrice;
const _toFiatPrice = const _toFiatPrice = assetsData[_toAssetId].currentPrice;
assetsData[_toAssetId].currentPrice;
const _marketFiatPrice = marketPrice * _toFiatPrice; const _marketFiatPrice = marketPrice * _toFiatPrice;
const _toAmountStr = toAmount.toFixed(3); const _toAmountStr = toAmount.toFixed(3);
@ -130,11 +126,12 @@ export const SwapTokenContent = ({ initialSymbol, handleHsTransfer, onSuccess }:
setFromAmount('0'); setFromAmount('0');
}; };
const _onSwapSuccess = async (hasPending:boolean) => { const _onSwapSuccess = async (hasPending: boolean) => {
const _badgeColor = hasPending
const _badgeColor = hasPending ? EStyleSheet.value('$primaryBlue') : EStyleSheet.value('$primaryGreen'); ? EStyleSheet.value('$primaryBlue')
const _badgeIcon = hasPending ? "error-outline" : "check"; : EStyleSheet.value('$primaryGreen');
const _titleId = hasPending ? 'trade.swap_pending' : 'trade.swap_successful' const _badgeIcon = hasPending ? 'error-outline' : 'check';
const _titleId = hasPending ? 'trade.swap_pending' : 'trade.swap_successful';
const _body = hasPending ? intl.formatMessage({ id: 'trade.swap_pending_body' }) : undefined; const _body = hasPending ? intl.formatMessage({ id: 'trade.swap_pending_body' }) : undefined;
const headerContent = ( const headerContent = (
@ -190,7 +187,7 @@ export const SwapTokenContent = ({ initialSymbol, handleHsTransfer, onSuccess }:
const _existingPedingCount = pendingRequestsQuery.data?.length || 0; const _existingPedingCount = pendingRequestsQuery.data?.length || 0;
const pendingRequests = await pendingRequestsQuery.refetch(); const pendingRequests = await pendingRequestsQuery.refetch();
const _hasPending = pendingRequests.data?.length !== _existingPedingCount; const _hasPending = pendingRequests.data?.length !== _existingPedingCount;
onSuccess(); onSuccess();
setSwapping(false); setSwapping(false);
_onSwapSuccess(_hasPending); _onSwapSuccess(_hasPending);

Some files were not shown because too many files have changed in this diff Show More