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": {
"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';
export default EStyleSheet.create({
modalStyle: {
backgroundColor: '$primaryBackgroundColor',
margin:0,
paddingTop:32,
paddingBottom:8,
},
modalStyle: {
backgroundColor: '$primaryBackgroundColor',
margin: 0,
paddingTop: 32,
paddingBottom: 8,
},
sheetContent: {
backgroundColor: '$primaryBackgroundColor',
position:'absolute',
bottom:0,
left:0,
right:0,
zIndex:999
},
sheetContent: {
backgroundColor: '$primaryBackgroundColor',
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
zIndex: 999,
},
container:{
marginTop:16,
marginBottom:36,
paddingHorizontal:24,
alignItems:'center',
justifyContent:'space-between',
} as ViewStyle,
container: {
marginTop: 16,
marginBottom: 36,
paddingHorizontal: 24,
alignItems: 'center',
justifyContent: 'space-between',
} as ViewStyle,
imageStyle:{
marginTop:8,
height:150,
width:'100%',
} as ImageStyle,
imageStyle: {
marginTop: 8,
height: 150,
width: '100%',
} as ImageStyle,
textContainer:{
marginTop:32,
marginBottom:44,
} as ViewStyle,
textContainer: {
marginTop: 32,
marginBottom: 44,
} as ViewStyle,
title: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 20,
fontWeight: '800',
} as TextStyle,
title: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 20,
fontWeight: '800',
} as TextStyle,
bodyText: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 16,
fontWeight: '600',
marginTop:4,
} as TextStyle,
bodyText: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 16,
fontWeight: '600',
marginTop: 4,
} as TextStyle,
btnText:{
color:'$pureWhite'
} as TextStyle,
btnText: {
color: '$pureWhite',
} as TextStyle,
button:{
button: {
backgroundColor: '$primaryBlue',
minWidth: 150,
paddingVertical: 16,
marginVertical: 8,
borderRadius: 32,
justifyContent: 'center',
alignItems: 'center',
} as ViewStyle,
backgroundColor:'$primaryBlue',
minWidth:150,
paddingVertical:16,
marginVertical:8,
borderRadius:32,
justifyContent:'center',
alignItems:'center'
} as ViewStyle,
actionPanel:{
width:'100%',
flexDirection:'row',
flexWrap:'wrap',
justifyContent:'space-around',
alignItems:'center',
} 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 EStyleSheet from "react-native-extended-stylesheet"
import { ImageStyle } from "react-native-fast-image"
import { ViewStyle } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
import { ImageStyle } from 'react-native-fast-image';
export default EStyleSheet.create({
hiveEngineWrapper: {
position: 'absolute',
top: -6,
right: 4,
borderRadius: 10,
padding: 1,
backgroundColor: '$pureWhite',
} as ViewStyle,
hiveEngineLogo: {
height: 14,
width: 14
} as ImageStyle,
logo: {
height: 30,
width: 30,
} as ImageStyle,
})
hiveEngineWrapper: {
position: 'absolute',
top: -6,
right: 4,
borderRadius: 10,
padding: 1,
backgroundColor: '$pureWhite',
} as ViewStyle,
hiveEngineLogo: {
height: 14,
width: 14,
} as ImageStyle,
logo: {
height: 30,
width: 30,
} as ImageStyle,
});

View File

@ -12,45 +12,45 @@ interface WritePostButtonProps {
onPress: () => void;
}
export const WritePostButton = forwardRef(({ placeholderId: placeholder, onPress }: WritePostButtonProps, ref) => {
const intl = useIntl();
export const WritePostButton = forwardRef(
({ placeholderId: placeholder, onPress }: WritePostButtonProps, ref) => {
const intl = useIntl();
const animatedContainer = useRef<AnimatedView>();
const animatedContainer = useRef<AnimatedView>();
const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn);
const currentAccount = useAppSelector((state) => state.account.currentAccount);
const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn);
const currentAccount = useAppSelector((state) => state.account.currentAccount);
useImperativeHandle(ref, () => ({
bounce: () => {
console.log('bouncing');
if (animatedContainer.current) {
animatedContainer.current.swing(1000);
useImperativeHandle(ref, () => ({
bounce: () => {
console.log('bouncing');
if (animatedContainer.current) {
animatedContainer.current.swing(1000);
}
},
}));
const _onPress = () => {
if (!isLoggedIn) {
showLoginAlert({ intl });
return;
}
},
}));
if (onPress) {
onPress();
}
};
const _onPress = () => {
if (!isLoggedIn) {
showLoginAlert({ intl });
return;
}
if (onPress) {
onPress();
}
};
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>
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>
</AnimatedView>
);
});
</TouchableOpacity>
</AnimatedView>
);
},
);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,6 @@
import React, { Component } from 'react';
import { View } from 'react-native';
import { useSelector } from 'react-redux';
import { connect } from 'react-redux';
import { useSelector, connect } from 'react-redux';
// Constants
// Components
@ -53,7 +52,6 @@ class TitleAreaView extends Component {
const { isDarkTheme } = this.props;
return (
<View style={[globalStyles.containerHorizontal16, { height: Math.max(maxHeight, height) }]}>
<TextInput
style={[styles.textInput, { height: Math.max(maxHeight, height) }]}
placeholderTextColor={isDarkTheme ? '#526d91' : '#c1c5c7'}
@ -71,19 +69,13 @@ class TitleAreaView extends Component {
onChangeText={(textT) => this._handleOnChange(textT)}
value={text}
/>
</View>
);
}
}
const mapStateToProps = (state) => ({
isDarkTheme: state.application.isDarkTheme,
});
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';
// Components
import { useSelector } from 'react-redux';
import { TextInput } from '../../textInput';
import { Icon } from '../../icon';
// Utils
@ -20,7 +21,6 @@ import { getResizedAvatar } from '../../../utils/image';
// Styles
import styles from './formInputStyles';
import { useSelector } from 'react-redux';
interface Props extends TextInputProps {
type: string;
@ -133,7 +133,7 @@ const FormInputView = ({
const _renderInfoIconWithPopover = () => (
<View style={styles.infoIconContainer}>
<TouchableOpacity ref={touchableRef} onPress={_handleInfoPress}>
<Icon iconType={'MaterialIcons'} name="info-outline" style={styles.infoIcon} />
<Icon iconType="MaterialIcons" name="info-outline" style={styles.infoIcon} />
</TouchableOpacity>
<Popover
backgroundStyle={styles.overlay}

View File

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

View File

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

View File

@ -1,272 +1,252 @@
import React, { useEffect, useState, useMemo } from 'react'
import { useIntl } from 'react-intl'
import { View, Alert } from 'react-native'
import { ProfileStats, StatsData } from './profileStats'
import { MainButton } from '../../..'
import { addFavorite, checkFavorite, deleteFavorite } from '../../../../providers/ecency/ecency'
import { followUser, getFollows, getRelationship, getUser } from '../../../../providers/hive/dhive'
import { getRcPower, getVotingPower } from '../../../../utils/manaBar'
import styles from './quickProfileStyles'
import { ProfileBasic } from './profileBasic'
import { parseReputation } from '../../../../utils/user'
import React, { useEffect, useState, useMemo } from 'react';
import { useIntl } from 'react-intl';
import { View, Alert } from 'react-native';
import { ProfileStats, StatsData } from './profileStats';
import { MainButton } from '../../..';
import { addFavorite, checkFavorite, deleteFavorite } from '../../../../providers/ecency/ecency';
import { followUser, getFollows, getRelationship, getUser } from '../../../../providers/hive/dhive';
import { getRcPower, getVotingPower } from '../../../../utils/manaBar';
import styles from './quickProfileStyles';
import { ProfileBasic } from './profileBasic';
import { parseReputation } from '../../../../utils/user';
import { default as ROUTES } from '../../../../constants/routeNames';
import { ActionPanel } from './actionPanel'
import { getTimeFromNowNative } from '../../../../utils/time'
import { useAppDispatch, useAppSelector } from '../../../../hooks'
import { toastNotification } from '../../../../redux/actions/uiAction'
import bugsnapInstance from '../../../../config/bugsnag'
import RootNavigation from '../../../../navigation/rootNavigation'
import { ActionPanel } from './actionPanel';
import { getTimeFromNowNative } from '../../../../utils/time';
import { useAppDispatch, useAppSelector } from '../../../../hooks';
import { toastNotification } from '../../../../redux/actions/uiAction';
import bugsnapInstance from '../../../../config/bugsnag';
import RootNavigation from '../../../../navigation/rootNavigation';
interface QuickProfileContentProps {
username: string,
onClose: () => void;
username: string;
onClose: () => void;
}
export const QuickProfileContent = ({
username,
onClose
}: QuickProfileContentProps) => {
const intl = useIntl();
const dispatch = useAppDispatch();
export const QuickProfileContent = ({ username, onClose }: QuickProfileContentProps) => {
const intl = useIntl();
const dispatch = useAppDispatch();
const currentAccount = useAppSelector((state) => state.account.currentAccount);
const pinCode = useAppSelector((state) => state.application.pin);
const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn);
const currentAccount = useAppSelector((state) => state.account.currentAccount);
const pinCode = useAppSelector((state) => state.application.pin);
const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn);
const [isLoading, setIsLoading] = useState(false);
const [user, setUser] = useState(null);
const [follows, setFollows] = useState(null);
const [isFollowing, setIsFollowing] = useState(false);
const [isMuted, setIsMuted] = useState(false);
const [isFavourite, setIsFavourite] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [user, setUser] = useState(null);
const [follows, setFollows] = useState(null);
const [isFollowing, setIsFollowing] = useState(false);
const [isMuted, setIsMuted] = useState(false);
const [isFavourite, setIsFavourite] = useState(false);
const isOwnProfile = currentAccount && currentAccount.name === username;
const currentAccountName = currentAccount ? currentAccount.name : null;
const isProfileLoaded = (user && follows) ? true : false;
const isOwnProfile = currentAccount && currentAccount.name === username;
const currentAccountName = currentAccount ? currentAccount.name : null;
const isProfileLoaded = !!(user && follows);
useEffect(() => {
if (username) {
_fetchUser();
_fetchExtraUserData();
} else {
setUser(null);
useEffect(() => {
if (username) {
_fetchUser();
_fetchExtraUserData();
} else {
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 {
const _user = await getUser(username, isOwnProfile);
setUser(_user)
} catch (error) {
setIsLoading(false);
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 () => {
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 () => {
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);
}
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)
}
if (onClose) {
onClose();
}
};
const _onFavouritePress = async () => {
try {
setIsLoading(true);
let favoriteAction;
// extract prop values
let _votingPower = '';
let _resourceCredits = '';
let _followerCount = 0;
let _followingCount = 0;
let _postCount = 0;
let _about = '';
let _reputation = 0;
let _createdData = null;
if (isFavourite) {
favoriteAction = deleteFavorite;
} else {
favoriteAction = addFavorite;
}
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);
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(),
);
}
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[];
//UI CALLBACKS
const _openFullProfile = () => {
let params = {
username,
reputation: user ? user.reputation : null
};
RootNavigation.navigate({
name: ROUTES.SCREENS.PROFILE,
params,
key: username,
});
if (onClose) {
onClose();
}
}
//extract prop values
let _votingPower = '';
let _resourceCredits = '';
let _followerCount = 0;
let _followingCount = 0;
let _postCount = 0;
let _about = '';
let _reputation = 0;
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>
)
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';
export default EStyleSheet.create({
modalStyle: {
backgroundColor: '$primaryBackgroundColor',
margin:0,
paddingTop:32,
marginHorizontal:24,
paddingBottom: getBottomSpace() + 8,
},
modalStyle: {
backgroundColor: '$primaryBackgroundColor',
margin: 0,
paddingTop: 32,
marginHorizontal: 24,
paddingBottom: getBottomSpace() + 8,
},
sheetContent: {
backgroundColor: '$primaryBackgroundColor',
},
sheetContent: {
backgroundColor: '$primaryBackgroundColor',
},
container:{
alignItems:'center',
marginHorizontal:16
} as ViewStyle,
container: {
alignItems: 'center',
marginHorizontal: 16,
} as ViewStyle,
image:{
width:128,
height:128,
borderRadius:64,
backgroundColor: '$primaryGray'
} as ImageStyle,
image: {
width: 128,
height: 128,
borderRadius: 64,
backgroundColor: '$primaryGray',
} as ImageStyle,
textContainer:{
marginTop:32,
marginBottom:44,
} as ViewStyle,
textContainer: {
marginTop: 32,
marginBottom: 44,
} as ViewStyle,
title: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 18,
fontWeight: 'bold',
marginTop:32,
} as TextStyle,
title: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 18,
fontWeight: 'bold',
marginTop: 32,
} as TextStyle,
statValue: {
fontFamily:'$editorFont',
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 34,
fontWeight: 'normal',
} as TextStyle,
statValue: {
fontFamily: '$editorFont',
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 34,
fontWeight: 'normal',
} as TextStyle,
statLabel: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 16,
fontWeight: 'normal',
} as TextStyle,
statLabel: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 16,
fontWeight: 'normal',
} as TextStyle,
bodyText: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 18,
marginTop: 6,
} as TextStyle,
bodyText: {
color: '$primaryBlack',
alignSelf: 'center',
textAlign: 'center',
fontSize: 18,
marginTop:6,
} as TextStyle,
btnText: {
color: '$pureWhite',
} as TextStyle,
button: {
marginTop: 40,
backgroundColor: '$primaryBlue',
paddingHorizontal: 44,
paddingVertical: 16,
borderRadius: 32,
justifyContent: 'center',
alignItems: 'center',
} as ViewStyle,
btnText:{
color:'$pureWhite'
} as TextStyle,
actionPanel: {
position: 'absolute',
right: 0,
top: 0,
flexDirection: 'row',
alignItems: 'center',
} as ViewStyle,
button:{
marginTop: 40,
backgroundColor:'$primaryBlue',
paddingHorizontal:44,
paddingVertical:16,
borderRadius:32,
justifyContent:'center',
alignItems:'center'
} 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
})
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 { findNodeHandle, NativeModules, View, TouchableOpacity, Text, Alert } from "react-native";
import { useAppSelector } from "../../../hooks";
import { PulseAnimation } from "../../animations";
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react';
import { findNodeHandle, NativeModules, View, TouchableOpacity, Text, Alert } from 'react-native';
import { Rect } from 'react-native-modal-popover/lib/PopoverGeometry';
import { useAppSelector } from '../../../hooks';
import { PulseAnimation } from '../../animations';
import { isVoted as isVotedFunc, isDownVoted as isDownVotedFunc } from '../../../utils/postParser';
import Icon from "../../icon";
import Icon from '../../icon';
import styles from './children.styles';
import { FormattedCurrency } from "../../formatedElements";
import { Rect } from "react-native-modal-popover/lib/PopoverGeometry";
import { PostTypes } from "../../../constants/postTypes";
import { FormattedCurrency } from '../../formatedElements';
import { PostTypes } from '../../../constants/postTypes';
interface UpvoteButtonProps {
content: any,
activeVotes: any[],
isShowPayoutValue?: boolean,
boldPayout?: boolean,
parentType?: PostTypes;
onUpvotePress: (anchorRect: Rect, onVotingStart: (status:number)=>void) => void,
onPayoutDetailsPress: (anchorRef: Rect) => void,
content: any;
activeVotes: any[];
isShowPayoutValue?: boolean;
boldPayout?: boolean;
parentType?: PostTypes;
onUpvotePress: (anchorRect: Rect, onVotingStart: (status: number) => void) => void;
onPayoutDetailsPress: (anchorRef: Rect) => void;
}
export const UpvoteButton = ({
content,
activeVotes,
isShowPayoutValue,
boldPayout,
onUpvotePress,
onPayoutDetailsPress
content,
activeVotes,
isShowPayoutValue,
boldPayout,
onUpvotePress,
onPayoutDetailsPress,
}: UpvoteButtonProps) => {
const upvoteRef = useRef(null);
const detailsRef = useRef(null);
const upvoteRef = useRef(null);
const detailsRef = useRef(null);
const currentAccount = useAppSelector((state) => state.account.currentAccount);
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);
const [isDownVoted, setIsDownVoted] = useState<any>(null);
useEffect(() => {
_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();
}, [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 _isVoted = await isVotedFunc(activeVotes, currentAccount?.name);
const _isDownVoted = await isDownVotedFunc(activeVotes, currentAccount?.name);
const payoutLimitHit = totalPayout >= maxPayout;
const _shownPayout = payoutLimitHit && maxPayout > 0 ? maxPayout : totalPayout;
let iconName = 'upcircleo';
const iconType = 'AntDesign';
let downVoteIconName = 'downcircleo';
setIsVoted(_isVoted && parseInt(_isVoted, 10) / 10000);
setIsDownVoted(_isDownVoted && (parseInt(_isDownVoted, 10) / 10000) * -1);
if (isVoted) {
iconName = 'upcircle';
}
}, [activeVotes]);
if (isDownVoted) {
downVoteIconName = 'downcircle';
}
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();
}
}
_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>
return (
<View style={styles.container}>
<TouchableOpacity ref={upvoteRef} onPress={_onPress} style={styles.upvoteButton}>
{/* <Fragment>
{isVoting ? (
<View style={{ width: 19 }}>
<PulseAnimation
@ -130,34 +112,32 @@ export const UpvoteButton = ({
/>
</View>
) : ( */}
<View hitSlop={{ top: 10, bottom: 10, left: 10, right: 5 }}>
<Icon
style={[styles.upvoteIcon, isDownVoted && { color: '#ec8b88' }]}
active={!currentAccount}
iconType={iconType}
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 hitSlop={{ top: 10, bottom: 10, left: 10, right: 5 }}>
<Icon
style={[styles.upvoteIcon, isDownVoted && { color: '#ec8b88' }]}
active={!currentAccount}
iconType={iconType}
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 File

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

View File

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

View File

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

View File

@ -50,7 +50,7 @@ export const PostHtmlRenderer = memo(
body = body
.replace(/<center>/g, '<div class="text-center">')
.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, '');
const _minTableColWidth = contentWidth / 3 - 12;
@ -278,7 +278,6 @@ export const PostHtmlRenderer = memo(
props.style = props.tnode.parent.tagName === 'li' ? styles.pLi : styles.p;
props.onPress = !props.onPress && handleOnContentPress ? handleOnContentPress : props.onPress;
return <TDefaultRenderer {...props} />;
};
@ -399,7 +398,7 @@ export const PostHtmlRenderer = memo(
customHTMLElementModels={customHTMLElementModels}
renderersProps={renderersProps}
WebView={WebView}
pressableHightlightColor={'transparent'}
pressableHightlightColor="transparent"
/>
);
},

View File

@ -87,7 +87,7 @@ export default EStyleSheet.create({
color: '$primaryRed',
} as TextStyle,
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,
} as TextStyle,
revealButton: {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,7 +9,7 @@ const QuickReplyModal = () => {
const dispatch = useAppDispatch();
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 _onClose = () => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -31,13 +31,13 @@ import {
* ************************************
*/
export const getFiatHbdRate = (fiatCode:string) =>
export const getFiatHbdRate = (fiatCode: string) =>
ecencyApi
.get(`/private-api/market-data/${fiatCode}/hbd`)
.then((resp) => resp.data)
.catch((err) => {
bugsnagInstance.notify(err);
//TODO: save currency rate of offline values
// TODO: save currency rate of offline values
return 1;
});
@ -53,7 +53,7 @@ export const getLatestQuotes = async (currencyRate: number): Promise<LatestMarke
const data = convertLatestQuotes(res.data, currencyRate);
console.log('parsed quotes data', data, currencyRate);
//TODO fetch engine quotes here
// TODO fetch engine quotes here
return data;
} catch (error) {
@ -126,8 +126,8 @@ export const addDraft = async (draft: Object) => {
const res = await ecencyApi.post('/private-api/drafts-add', newDraft);
const rawData = res.data?.drafts;
if(!rawData){
throw new Error("Invalid response, drafts data not returned")
if (!rawData) {
throw new Error('Invalid response, drafts data not returned');
}
const data = rawData.length > 0 ? rawData.map(convertDraft) : [];
@ -526,7 +526,7 @@ export const searchPath = async (q: string) => {
* @param random random
* @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 {
const data = {
q,
@ -549,7 +549,7 @@ export const searchAccount = async (q: string = '', limit: number = 20, random:
* @param random random
* @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 {
const data = {
q,
@ -782,7 +782,7 @@ export const getPromotedEntries = async (username: string) => {
* post inapp purchase method to call
* @param data PurchaseRequestData
* @returns
**/
* */
export const purchaseOrder = (data: PurchaseRequestData) =>
api
.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, token?: Token, metrics?: EngineMetric, tokenStatus?:TokenStatus) => {
export const convertEngineToken = (
balanceObj: TokenBalance,
token?: Token,
metrics?: EngineMetric,
tokenStatus?: TokenStatus,
) => {
if (!balanceObj) {
return null;
}
@ -37,50 +50,44 @@ export const convertEngineToken = (balanceObj: TokenBalance, token?: Token, metr
} as HiveEngineToken;
};
export const convertRewardsStatus = (rawData: any) => {
return {
symbol:rawData.symbol,
pendingToken:rawData.pending_token,
precision:rawData.precision,
pendingRewards: rawData.pending_token / Math.pow(10, rawData.precision)
} as TokenStatus
}
symbol: rawData.symbol,
pendingToken: rawData.pending_token,
precision: rawData.precision,
pendingRewards: rawData.pending_token / Math.pow(10, rawData.precision),
} as TokenStatus;
};
export const convertMarketData = (rawData: any) => {
if(!rawData){
if (!rawData) {
return null;
}
return {
quoteVolume:parseFloat(rawData.quoteVolume),
baseVolume:parseFloat(rawData.baseVolume),
low:parseFloat(rawData.low),
close:parseFloat(rawData.close),
high:parseFloat(rawData.high),
open:parseFloat(rawData.open),
timestamp:rawData.timestamp,
} as MarketData
}
quoteVolume: parseFloat(rawData.quoteVolume),
baseVolume: parseFloat(rawData.baseVolume),
low: parseFloat(rawData.low),
close: parseFloat(rawData.close),
high: parseFloat(rawData.high),
open: parseFloat(rawData.open),
timestamp: rawData.timestamp,
} as MarketData;
};
export const convertEngineHistory = (rawData: any) => {
return {
_id:rawData._id,
blockNumber:rawData.blockNumber,
transactionId:rawData.transactionId,
timestamp:rawData.timestamp * 1000,
operation:rawData.operation,
from:rawData.from,
to:rawData.to,
symbol:rawData.symbol,
quantity:parseFloat(rawData.quantity),
memo:rawData.memo,
account:rawData.account,
authorperm:rawData.authorperm,
} as HistoryItem
}
_id: rawData._id,
blockNumber: rawData.blockNumber,
transactionId: rawData.transactionId,
timestamp: rawData.timestamp * 1000,
operation: rawData.operation,
from: rawData.from,
to: rawData.to,
symbol: rawData.symbol,
quantity: parseFloat(rawData.quantity),
memo: rawData.memo,
account: rawData.account,
authorperm: rawData.authorperm,
} as HistoryItem;
};

View File

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

View File

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

View File

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

View File

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

View File

@ -33,7 +33,7 @@ interface MediaUploadVars {
addToUploads: boolean;
}
/** GET QUERIES **/
/** GET QUERIES * */
export const useMediaQuery = () => {
const intl = useIntl();
@ -57,7 +57,7 @@ export const useSnippetsQuery = () => {
});
};
/** ADD UPDATE MUTATIONS **/
/** ADD UPDATE MUTATIONS * */
export const useAddToUploadsMutation = () => {
const intl = useIntl();
@ -71,7 +71,7 @@ export const useAddToUploadsMutation = () => {
},
onError: (error) => {
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]);
} else {
dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' })));
@ -234,7 +234,7 @@ export const useSnippetsMutation = () => {
);
};
/** DELETE MUTATIONS **/
/** DELETE MUTATIONS * */
export const useMediaDeleteMutation = () => {
const queryClient = useQueryClient();

View File

@ -10,7 +10,7 @@ export const initQueryClient = () => {
});
const client = new QueryClient({
//Query client configurations go here...
// Query client configurations go here...
defaultOptions: {
queries: {
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';
if(_isSuccess){
//Cherry pick whihc queries to dehydrate for persistance
switch(query.queryKey[0]){
if (_isSuccess) {
// Cherry pick whihc queries to dehydrate for persistance
switch (query.queryKey[0]) {
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:
return query.queryKey[2] === '' //only dehydrate first page of notifications
return query.queryKey[2] === ''; // only dehydrate first page of notifications
default:
return true;
}
}
console.log("status error for dehydration", query.queryKey)
console.log('status error for dehydration', query.queryKey);
return false;
}
};
return {
client,
persistOptions: {
persister: asyncStoragePersister, dehydrateOptions: {
shouldDehydrateQuery: _shouldDehdrateQuery
}
persister: asyncStoragePersister,
dehydrateOptions: {
shouldDehydrateQuery: _shouldDehdrateQuery,
},
},
} as PersistQueryClientProviderProps;
};

View File

@ -122,7 +122,7 @@ export const useDiscussionQuery = (_author?: string, _permlink?: string) => {
);
useEffect(() => {
const _data = injectPostCache(query.data, cachedComments, cachedVotes, lastCacheUpdate);
const _data = injectPostCache(query.data, cachedComments, cachedVotes, lastCacheUpdate);
setData(_data);
}, [query.data, cachedComments, cachedVotes]);
@ -130,7 +130,6 @@ export const useDiscussionQuery = (_author?: string, _permlink?: string) => {
restructureData();
}, [data]);
// traverse discussion collection to curate sections
const restructureData = async () => {
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 { 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 { delay } from '../../../utils/editor';
import { injectPostCache, injectVoteCache, mapDiscussionToThreads } from '../../../utils/postParser';
import {
injectPostCache,
injectVoteCache,
mapDiscussionToThreads,
} from '../../../utils/postParser';
import { useAppSelector } from '../../../hooks';
export const useWavesQuery = (host: string) => {
const queryClient = useQueryClient();
const cache = useAppSelector(state => state.cache);
const mutes = useAppSelector(state => state.account.currentAccount.mutes);
const cache = useAppSelector((state) => state.cache);
const mutes = useAppSelector((state) => state.account.currentAccount.mutes);
const cacheRef = useRef(cache);
const cachedVotes = cache.votesCollection
const lastCacheUpdate = cache.lastUpdate
const cachedVotes = cache.votesCollection;
const lastCacheUpdate = cache.lastUpdate;
const [isRefreshing, setIsRefreshing] = useState(false);
const [isLoading, setIsLoading] = useState(true);
@ -35,102 +29,99 @@ export const useWavesQuery = (host: string) => {
const wavesIndexCollection = useRef<{ [key: string]: string }>({});
const _initialContainerPermlinks = useMemo(() =>
queryClient.getQueryData<string[]>([QUERIES.WAVES.INITIAL_CONTAINERS, host]) || [], []);
const _initialContainerPermlinks = useMemo(
() => queryClient.getQueryData<string[]>([QUERIES.WAVES.INITIAL_CONTAINERS, host]) || [],
[],
);
const [permlinksBucket, setPermlinksBucket] = useState<string[]>(_initialContainerPermlinks);
// query initialization
const wavesQueries = useQueries({
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),
initialData: [],
})),
});
//hook to update cache reference,
//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
//supported by useQueries
// hook to update cache reference,
// 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
// supported by useQueries
useEffect(() => {
cacheRef.current = cache;
}, [cache])
}, [cache]);
useEffect(() => {
_fetchPermlinks('', true);
}, [])
}, []);
useEffect(() => {
if (!!permlinksBucket.length) {
//if first elements permlinks do not match, means there is a new container, push at first
if (permlinksBucket.length) {
// if first elements permlinks do not match, means there is a new container, push at first
if (permlinksBucket[0] !== activePermlinks[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 {
activePermlinks.push(permlinksBucket[activePermlinks.length]);
}
setActivePermlinks([...activePermlinks]);
}
}, [permlinksBucket])
}, [permlinksBucket]);
useEffect(() => {
const _latestData = wavesQueries.lastItem?.data;
if (!_latestData || _latestData.length < 10) {
_fetchNextPage();
}
}, [wavesQueries.lastItem?.data])
}, [wavesQueries.lastItem?.data]);
useEffect(() => {
//check cache is recently updated and take post path
// check cache is recently updated and take post path
if (lastCacheUpdate) {
const _timeElapsed = new Date().getTime() - lastCacheUpdate.updatedAt
const _timeElapsed = new Date().getTime() - lastCacheUpdate.updatedAt;
if (lastCacheUpdate.type === 'vote' && _timeElapsed < 5000) {
_injectPostCache(lastCacheUpdate.postPath)
_injectPostCache(lastCacheUpdate.postPath);
}
}
}, [lastCacheUpdate])
}, [lastCacheUpdate]);
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 _containerIndex = activePermlinks.indexOf(_containerPermlink)
const _containerIndex = activePermlinks.indexOf(_containerPermlink);
const _voteCache = cachedVotes[postPath];
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;
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];
if (_post) {
//inject cache and set query data
// inject cache and set query data
const _cPost = injectVoteCache(_post, _voteCache);
_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) => {
setIsLoading(true);
try {
const query: any = {
account: host,
start_author: !!startPermlink ? host : '',
start_author: startPermlink ? host : '',
start_permlink: startPermlink,
limit: 5,
observer: '',
@ -139,56 +130,53 @@ export const useWavesQuery = (host: string) => {
const result = await getAccountPosts(query);
const _fetchedPermlinks = result.map(post => post.permlink);
const _fetchedPermlinks = result.map((post) => post.permlink);
console.log('permlinks fetched', _fetchedPermlinks);
const _permlinksBucket = refresh ? _fetchedPermlinks : [...permlinksBucket, ..._fetchedPermlinks];
const _permlinksBucket = refresh
? _fetchedPermlinks
: [...permlinksBucket, ..._fetchedPermlinks];
setPermlinksBucket(_permlinksBucket);
if (refresh) {
queryClient.setQueryData([QUERIES.WAVES.INITIAL_CONTAINERS, host], _permlinksBucket);
//precautionary delay of 200ms to let state update before concluding promise,
//it is effective for waves refresh routine.
await delay(200)
// precautionary delay of 200ms to let state update before concluding promise,
// it is effective for waves refresh routine.
await delay(200);
}
} 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) => {
console.log('fetching waves from:', host, pagePermlink);
const response = await getDiscussionCollection(host, pagePermlink);
//inject cache here...
// inject cache here...
const _cachedComments = cacheRef.current.commentsCollection;
const _cachedVotes = cacheRef.current.votesCollection;
const _lastCacheUpdate = cacheRef.current.lastCacheUpdate
const _lastCacheUpdate = cacheRef.current.lastCacheUpdate;
const _cResponse = injectPostCache(response, _cachedComments, _cachedVotes, _lastCacheUpdate);
const _threadedComments = await mapDiscussionToThreads(_cResponse, host, pagePermlink, 1);
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) => {
wavesIndexCollection.current[`${item.author}/${item.permlink}`] = pagePermlink
})
wavesIndexCollection.current[`${item.author}/${item.permlink}`] = pagePermlink;
});
console.log('new waves fetched', _threadedComments);
return _threadedComments || [];
};
const _fetchNextPage = () => {
const lastPage = wavesQueries.lastItem;
@ -199,17 +187,15 @@ export const useWavesQuery = (host: string) => {
const _nextPagePermlink = permlinksBucket[activePermlinks.length];
if (_nextPagePermlink && !activePermlinks.includes(_nextPagePermlink)) {
console.log("updating next page permlink", _nextPagePermlink)
console.log('updating next page permlink', _nextPagePermlink);
activePermlinks.push(_nextPagePermlink);
setActivePermlinks([...activePermlinks]);
} else {
console.log("fetching new containers", permlinksBucket.lastItem)
_fetchPermlinks(permlinksBucket.lastItem)
console.log('fetching new containers', permlinksBucket.lastItem);
_fetchPermlinks(permlinksBucket.lastItem);
}
};
const _refresh = async () => {
setIsRefreshing(true);
setPermlinksBucket([]);
@ -219,38 +205,32 @@ export const useWavesQuery = (host: string) => {
setIsRefreshing(false);
};
const _data = unionBy(...wavesQueries.map((query) => query.data), 'url');
const _filteredData = useMemo(() =>
_data.filter(post => isArray(mutes) ? mutes.indexOf(post?.author) < 0 : true),
[mutes, _data])
const _filteredData = useMemo(
() => _data.filter((post) => (isArray(mutes) ? mutes.indexOf(post?.author) < 0 : true)),
[mutes, _data],
);
const _lastestWavesFetch = async () => {
await _fetchPermlinks('', true);
const _prevLatestWave = _filteredData[0]
const _prevLatestWave = _filteredData[0];
const _firstQuery = wavesQueries[0];
if(!_firstQuery){
if (!_firstQuery) {
return [];
}
const queryResponse = await _firstQuery.refetch();
const _newData:any[] = queryResponse.data || [];
const _newData: any[] = queryResponse.data || [];
//check if new waves are available
const _lastIndex = _newData?.findIndex(item =>
( item.author + item.permlink === _prevLatestWave.author + _prevLatestWave.permlink));
// check if new waves are available
const _lastIndex = _newData?.findIndex(
(item) => item.author + item.permlink === _prevLatestWave.author + _prevLatestWave.permlink,
);
let _newWaves:any[] = []
let _newWaves: any[] = [];
if (_lastIndex && _lastIndex !== 0) {
if (_lastIndex < 0) {
_newWaves = _newData?.slice(0, 5) || [];
@ -259,10 +239,8 @@ export const useWavesQuery = (host: string) => {
}
}
return _newWaves
}
return _newWaves;
};
return {
data: _filteredData,
@ -274,26 +252,21 @@ export const useWavesQuery = (host: string) => {
};
};
export const usePublishWaveMutation = () => {
const queryClient = useQueryClient();
// id is options, if no id is provided program marks all notifications as read;
const _mutationFn = async (cachePostData: any) => {
//TODO: lates port wave publishing here or introduce post publishing mutation;
if (cachePostData) { //TODO: expand to check multiple wave hosts;{
// TODO: lates port wave publishing here or introduce post publishing mutation;
if (cachePostData) {
// TODO: expand to check multiple wave hosts;{
const _host = cachePostData.parent_author;
console.log('returning waves host', _host);
return _host;
}
throw new Error("invalid mutations data")
throw new Error('invalid mutations data');
};
const _options: UseMutationOptions<string, unknown, any, void> = {
@ -314,11 +287,10 @@ export const usePublishWaveMutation = () => {
queryData.splice(0, 0, cacheCommentData);
queryClient.setQueryData(_queryKey, queryData);
}
},
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 _queryKey = queriesData[0][0];
queryClient.invalidateQueries(_queryKey);
@ -328,8 +300,6 @@ export const usePublishWaveMutation = () => {
return useMutation(_mutationFn, _options);
};
export const fetchLatestWavesContainer = async (host) => {
const query: any = {
account: host,
@ -346,8 +316,8 @@ export const fetchLatestWavesContainer = async (host) => {
console.log('lates waves post', host, _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;
}
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -52,9 +52,9 @@ export const DelegationsModal = forwardRef(({}, ref) => {
}
}, [mode, showModal]);
const _getVestingDelegations = async (startUsername: string = '') => {
const _getVestingDelegations = async (startUsername = '') => {
let resData: any = [];
let limit = 1000;
const limit = 1000;
const response = await getVestingDelegations(currentAccount.username, startUsername, limit);
resData = response.map(
@ -132,7 +132,7 @@ export const DelegationsModal = forwardRef(({}, ref) => {
const title = intl.formatMessage({ id: `wallet.${mode}` });
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 subRightText =
mode === MODES.DELEGATEED && intl.formatMessage({ id: 'wallet.tap_update' });

View File

@ -15,33 +15,34 @@ interface RangeSelectorProps {
}
export const RangeSelector = ({ range, minRange, onRangeChange }: RangeSelectorProps) => {
const _onSelection = (range: number) => {
console.log('selection', range);
onRangeChange(range);
};
const _renderRangeButtons = FILTERS.filter((item) => item.value >= minRange).map((item: RangeOption) => (
<TouchableOpacity key={`range option-${item.value}`} onPress={() => _onSelection(item.value)}>
<View
style={{
...styles.rangeOptionWrapper,
backgroundColor: EStyleSheet.value(
item.value === range ? '$darkGrayBackground' : '$primaryLightBackground',
),
}}
>
<Text
const _renderRangeButtons = FILTERS.filter((item) => item.value >= minRange).map(
(item: RangeOption) => (
<TouchableOpacity key={`range option-${item.value}`} onPress={() => _onSelection(item.value)}>
<View
style={{
...styles.textRange,
color: EStyleSheet.value(item.value === range ? '$white' : '$primaryDarkText'),
...styles.rangeOptionWrapper,
backgroundColor: EStyleSheet.value(
item.value === range ? '$darkGrayBackground' : '$primaryLightBackground',
),
}}
>
{item.label}
</Text>
</View>
</TouchableOpacity>
));
<Text
style={{
...styles.textRange,
color: EStyleSheet.value(item.value === range ? '$white' : '$primaryDarkText'),
}}
>
{item.label}
</Text>
</View>
</TouchableOpacity>
),
);
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';
export default EStyleSheet.create({
modalStyle:{
modalStyle: {
flex: 1,
backgroundColor: '$primaryBackgroundColor',
margin: 0,
@ -23,7 +23,7 @@ export default EStyleSheet.create({
} as ViewStyle,
scrollContainer: {
flex:1,
flex: 1,
marginTop: 16,
marginBottom: 16,
} as ViewStyle,
@ -35,33 +35,30 @@ export default EStyleSheet.create({
} as TextStyle,
modalContainer: {
flex:1,
flex: 1,
marginBottom: 44,
paddingHorizontal: 24,
alignItems: 'center',
justifyContent: 'space-between',
} as ViewStyle,
sectionTextStyle : {
color:'$primaryBlack',
sectionTextStyle: {
color: '$primaryBlack',
fontSize: 16,
marginHorizontal: 16,
marginVertical:4,
marginVertical: 4,
} as TextStyle,
sectionSubTextStyle : {
color:'$iconColor',
sectionSubTextStyle: {
color: '$iconColor',
fontSize: 18,
marginHorizontal: 16,
marginVertical:16,
alignSelf:'center'
marginVertical: 16,
alignSelf: 'center',
} as TextStyle,
dragBtnContainer:{
padding:8
dragBtnContainer: {
padding: 8,
} as ViewStyle,
title: {
@ -83,12 +80,12 @@ export default EStyleSheet.create({
btnText: {
color: '$pureWhite',
textTransform: 'uppercase'
textTransform: 'uppercase',
} as TextStyle,
assetIconContainer:{
width:32,
marginLeft:16
assetIconContainer: {
width: 32,
marginLeft: 16,
},
button: {

View File

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

View File

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

View File

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

View File

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

View File

@ -2,12 +2,12 @@ import React, { useState, useRef, useEffect, useMemo } from 'react';
import { View } from 'react-native';
// Components
import FastImage from 'react-native-fast-image';
import { BasicHeader, IconButton, PostDisplay, PostOptionsModal } from '../../../components';
import styles from '../styles/postScreen.styles';
// Component
import { postQueries } from '../../../providers/queries';
import FastImage from 'react-native-fast-image';
const PostScreen = ({ route }) => {
const params = route.params || {};
@ -22,21 +22,23 @@ const PostScreen = ({ route }) => {
const getPostQuery = postQueries.useGetPostQuery(author, permlink, params.content);
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(() => {
return () => {
//clears FastImage RAM, not disk usage;
// clears FastImage RAM, not disk usage;
FastImage.clearMemoryCache();
}
}, [])
};
}, []);
useEffect(() => {
const post = getPostQuery.data;
if (post) {
const _fetchParent = post && post.depth > 0
&& post.parent_author && post.parent_permlink
&& !isWavePost;
const _fetchParent =
post && post.depth > 0 && post.parent_author && post.parent_permlink && !isWavePost;
if (_fetchParent) {
getParentPostQuery.setAuthor(post.parent_author);

View File

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

View File

@ -32,7 +32,6 @@ export const SwapTokenContent = ({ initialSymbol, handleHsTransfer, onSuccess }:
const dispatch = useAppDispatch();
const navigation = useNavigation();
const currentAccount = useAppSelector((state) => state.account.currentAccount);
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 _toAssetId = _toAssetSymbol === MarketAsset.HBD ? ASSET_IDS.HBD : ASSET_IDS.HIVE;
// queres
const assetsQuery = walletQueries.useAssetsQuery();
const pendingRequestsQuery = walletQueries.usePendingRequestsQuery(_fromAssetId);
// 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
const _onAssetChangeComplete = () => {
@ -93,8 +90,7 @@ export const SwapTokenContent = ({ initialSymbol, handleHsTransfer, onSuccess }:
const _fromAssetData = assetsData[_fromAssetId];
const _balance = _fromAssetData.balance;
const _fromFiatPrice = _fromAssetData.currentPrice;
const _toFiatPrice =
assetsData[_toAssetId].currentPrice;
const _toFiatPrice = assetsData[_toAssetId].currentPrice;
const _marketFiatPrice = marketPrice * _toFiatPrice;
const _toAmountStr = toAmount.toFixed(3);
@ -130,11 +126,12 @@ export const SwapTokenContent = ({ initialSymbol, handleHsTransfer, onSuccess }:
setFromAmount('0');
};
const _onSwapSuccess = async (hasPending:boolean) => {
const _badgeColor = hasPending ? EStyleSheet.value('$primaryBlue') : EStyleSheet.value('$primaryGreen');
const _badgeIcon = hasPending ? "error-outline" : "check";
const _titleId = hasPending ? 'trade.swap_pending' : 'trade.swap_successful'
const _onSwapSuccess = async (hasPending: boolean) => {
const _badgeColor = hasPending
? EStyleSheet.value('$primaryBlue')
: EStyleSheet.value('$primaryGreen');
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 headerContent = (

View File

@ -1,11 +1,9 @@
import React, { useEffect, useRef, useState } from "react";
import { MarketAsset, OrdersDataItem } from "../../../providers/hive-trade/hiveTrade.types";
import bugsnapInstance from "../../../config/bugsnag";
import { Alert } from "react-native";
import { getOrderBook } from "../../../providers/hive/dhive";
import { stripDecimalPlaces } from "../../../utils/number";
import React, { useEffect, useRef, useState } from 'react';
import { Alert } from 'react-native';
import { MarketAsset, OrdersDataItem } from '../../../providers/hive-trade/hiveTrade.types';
import bugsnapInstance from '../../../config/bugsnag';
import { getOrderBook } from '../../../providers/hive/dhive';
import { stripDecimalPlaces } from '../../../utils/number';
export namespace HiveMarket {
interface ProcessingResult {
@ -15,7 +13,7 @@ export namespace HiveMarket {
emptyOrderBook?: boolean;
}
function calculatePrice(intAmount: number, book: OrdersDataItem[], asset: "hive" | "hbd") {
function calculatePrice(intAmount: number, book: OrdersDataItem[], asset: 'hive' | 'hbd') {
let available = book[0][asset] / 1000;
let index = 0;
while (available < intAmount && book.length > index + 1) {
@ -29,8 +27,8 @@ export namespace HiveMarket {
try {
return await getOrderBook();
} catch (e) {
bugsnapInstance.notify(e)
Alert.alert("Order book is empty")
bugsnapInstance.notify(e);
Alert.alert('Order book is empty');
}
return null;
}
@ -39,7 +37,7 @@ export namespace HiveMarket {
buyOrderBook: OrdersDataItem[],
sellOrderBook: OrdersDataItem[],
fromAmount: number,
asset: string
asset: string,
): ProcessingResult {
if (buyOrderBook.length <= 0 || sellOrderBook.length <= 0) return { emptyOrderBook: true };
@ -48,19 +46,19 @@ export namespace HiveMarket {
let availableInOrderBook,
price = 0;
let firstPrice = Infinity;
let toAmount = 0;;
let toAmount = 0;
let resultToAmount;
if (asset === MarketAsset.HIVE) {
availableInOrderBook =
buyOrderBook.map((item) => item.hive).reduce((acc, item) => acc + item, 0) / 1000;
price = calculatePrice(fromAmount, buyOrderBook, "hive");
price = calculatePrice(fromAmount, buyOrderBook, 'hive');
toAmount = fromAmount * price;
firstPrice = +buyOrderBook[0].real_price;
} else if (asset === MarketAsset.HBD) {
availableInOrderBook =
sellOrderBook.map((item) => item.hbd).reduce((acc, item) => acc + item, 0) / 1000;
price = calculatePrice(fromAmount, sellOrderBook, "hbd");
price = calculatePrice(fromAmount, sellOrderBook, 'hbd');
toAmount = fromAmount / price;
firstPrice = +sellOrderBook[0].real_price;
}
@ -85,7 +83,7 @@ export namespace HiveMarket {
book?.bids ?? [],
book?.asks ?? [],
fromAmount,
asset
asset,
);
if (newToAmount) {
return newToAmount;
@ -94,7 +92,6 @@ export namespace HiveMarket {
}
}
export const useSwapCalculator = (
asset: MarketAsset,
fromAmount: number,
@ -110,7 +107,6 @@ export const useSwapCalculator = (
const assetRef = useRef(asset);
let updateInterval: any;
useEffect(() => {
@ -130,21 +126,16 @@ export const useSwapCalculator = (
});
}, [asset]);
useEffect(() => {
processOrderBook();
}, [fromAmount]);
const processOrderBook = () => {
const { tooMuchSlippage: _tooMuchSlippage, invalidAmount: _invalidAmount, toAmount: _toAmount } = HiveMarket.processHiveOrderBook(
buyOrderBook,
sellOrderBook,
fromAmount,
asset
);
const {
tooMuchSlippage: _tooMuchSlippage,
invalidAmount: _invalidAmount,
toAmount: _toAmount,
} = HiveMarket.processHiveOrderBook(buyOrderBook, sellOrderBook, fromAmount, asset);
setTooMuchSlippage(!!_tooMuchSlippage);
setOfferUnavailable(!!_invalidAmount);
if (_toAmount) {
@ -152,7 +143,6 @@ export const useSwapCalculator = (
}
};
const fetchOrderBook = async () => {
setIsLoading(true);
try {

View File

@ -2,26 +2,25 @@ import { ViewStyle } from 'react-native';
import EStyleSheet from 'react-native-extended-stylesheet';
export default EStyleSheet.create({
changeBtnContainer:{
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
justifyContent: 'center',
alignItems: 'center'
} as ViewStyle,
changeBtn: {
justifyContent:'center',
alignItems:'center',
backgroundColor: '$primaryLightBackground',
borderRadius: 28,
borderWidth: 8,
borderColor: '$primaryBackgroundColor',
} as ViewStyle,
changeBtnSize:{
height: 60,
width: 60,
} as ViewStyle,
})
changeBtnContainer: {
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
left: 0,
justifyContent: 'center',
alignItems: 'center',
} as ViewStyle,
changeBtn: {
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '$primaryLightBackground',
borderRadius: 28,
borderWidth: 8,
borderColor: '$primaryBackgroundColor',
} as ViewStyle,
changeBtnSize: {
height: 60,
width: 60,
} as ViewStyle,
});

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