diff --git a/index.js b/index.js index b23b34c52..bb2418f0a 100644 --- a/index.js +++ b/index.js @@ -3,14 +3,13 @@ import AppCenter from 'appcenter'; import { name as appName } from './app.json'; import 'core-js'; import 'intl'; -import 'intl/locale-data/jsonp/en-US' +import 'intl/locale-data/jsonp/en-US'; // set check frequency options const EcencyApp = require('./App').default; AppCenter.setLogLevel(AppCenter.LogLevel.VERBOSE); - // TODO Remove ignoreLogs when referenced issue is fixed properly // ref: https://github.com/ecency/ecency-mobile/issues/2466 // ignore warnings diff --git a/src/components/accountsBottomSheet/container/accountsBottomSheetContainer.tsx b/src/components/accountsBottomSheet/container/accountsBottomSheetContainer.tsx index 96056e0ee..ffc277240 100644 --- a/src/components/accountsBottomSheet/container/accountsBottomSheetContainer.tsx +++ b/src/components/accountsBottomSheet/container/accountsBottomSheetContainer.tsx @@ -1,12 +1,27 @@ import React, { useEffect, useRef, useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; +import { Alert } from 'react-native'; +import { useIntl } from 'react-intl'; import { navigate } from '../../../navigation/service'; import { removeOtherAccount, updateCurrentAccount } from '../../../redux/actions/accountAction'; -import { isPinCodeOpen, isRenderRequired, login, logout, logoutDone } from '../../../redux/actions/applicationActions'; +import { + isPinCodeOpen, + isRenderRequired, + login, + logout, + logoutDone, +} from '../../../redux/actions/applicationActions'; -import { getUserDataWithUsername, removeAllUserData, removePinCode, setAuthStatus, setExistUser, setPinCodeOpen } from '../../../realm/realm'; +import { + getUserDataWithUsername, + removeAllUserData, + removePinCode, + setAuthStatus, + setExistUser, + setPinCodeOpen, +} from '../../../realm/realm'; import { migrateToMasterKeyWithAccessToken, refreshSCToken, @@ -20,12 +35,10 @@ import { toggleAccountsBottomSheet } from '../../../redux/actions/uiAction'; import AUTH_TYPE from '../../../constants/authType'; import { getDigitPinCode, getMutes } from '../../../providers/hive/dhive'; import { setFeedPosts, setInitPosts } from '../../../redux/actions/postsAction'; -import { Alert } from 'react-native'; -import { useIntl } from 'react-intl'; import { useAppSelector } from '../../../hooks'; import { getUnreadNotificationCount } from '../../../providers/ecency/ecency'; import { decryptKey } from '../../../utils/crypto'; -import { getPointsSummary} from '../../../providers/ecency/ePoint'; +import { getPointsSummary } from '../../../providers/ecency/ePoint'; import { fetchSubscribedCommunities } from '../../../redux/actions/communitiesAction'; import { clearSubscribedCommunitiesCache } from '../../../redux/actions/cacheActions'; @@ -71,7 +84,6 @@ const AccountsBottomSheetContainer = ({ navigation }) => { dispatch(logout()); }; - const _handleSwitch = async (switchingAccount = {}) => { try { const accountData = accounts.filter( @@ -94,8 +106,12 @@ const AccountsBottomSheetContainer = ({ navigation }) => { //migreate account to use access token for master key auth type if (realmData[0].authType !== AUTH_TYPE.STEEM_CONNECT && realmData[0].accessToken === '') { - _currentAccount = await migrateToMasterKeyWithAccessToken(_currentAccount, realmData[0], pinHash); - } + _currentAccount = await migrateToMasterKeyWithAccessToken( + _currentAccount, + realmData[0], + pinHash, + ); + } //refresh access token const encryptedAccessToken = await refreshSCToken( @@ -112,10 +128,8 @@ const AccountsBottomSheetContainer = ({ navigation }) => { dispatch(updateCurrentAccount(_currentAccount)); dispatch(clearSubscribedCommunitiesCache()); - dispatch(fetchSubscribedCommunities(_currentAccount.username)) - } - - catch(error){ + dispatch(fetchSubscribedCommunities(_currentAccount.username)); + } catch (error) { Alert.alert( intl.formatMessage({ id: 'alert.fail', diff --git a/src/components/atoms/index.ts b/src/components/atoms/index.ts index c27b8824d..fcca39246 100644 --- a/src/components/atoms/index.ts +++ b/src/components/atoms/index.ts @@ -1,2 +1,2 @@ export * from './optionsModal'; -export * from './progressBar' \ No newline at end of file +export * from './progressBar'; diff --git a/src/components/atoms/progressBar/children/progresBarStyles.ts b/src/components/atoms/progressBar/children/progresBarStyles.ts index d9e17ae89..91c36720c 100644 --- a/src/components/atoms/progressBar/children/progresBarStyles.ts +++ b/src/components/atoms/progressBar/children/progresBarStyles.ts @@ -1,17 +1,17 @@ import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ - container:{ - backgroundColor:'$primaryLightBackground', - flexDirection:'row', - borderRadius:16, - height:16, - alignSelf:'stretch', - marginHorizontal:8, - marginBottom:12, - }, - filled:{ - borderRadius:16, - backgroundColor:'$primaryBlue' - }, + container: { + backgroundColor: '$primaryLightBackground', + flexDirection: 'row', + borderRadius: 16, + height: 16, + alignSelf: 'stretch', + marginHorizontal: 8, + marginBottom: 12, + }, + filled: { + borderRadius: 16, + backgroundColor: '$primaryBlue', + }, }); diff --git a/src/components/atoms/progressBar/container/progressBar.tsx b/src/components/atoms/progressBar/container/progressBar.tsx index 0f95da0f4..d4c655ea2 100644 --- a/src/components/atoms/progressBar/container/progressBar.tsx +++ b/src/components/atoms/progressBar/container/progressBar.tsx @@ -1,20 +1,15 @@ import React from 'react'; -import { View } from "react-native" +import { View } from 'react-native'; import styles from '../children/progresBarStyles'; - - -export const ProgressBar = ({ - progress -}) => { - - const containerStyle = {...styles.container}; - const filledStyle = {...styles.filled, flex:progress}; - const unfilledStyle = {flex:100 - progress} - return ( - - - - - ) -} \ No newline at end of file +export const ProgressBar = ({ progress }) => { + const containerStyle = { ...styles.container }; + const filledStyle = { ...styles.filled, flex: progress }; + const unfilledStyle = { flex: 100 - progress }; + return ( + + + + + ); +}; diff --git a/src/components/atoms/progressBar/index.ts b/src/components/atoms/progressBar/index.ts index 5c592bd57..fcf7ef606 100644 --- a/src/components/atoms/progressBar/index.ts +++ b/src/components/atoms/progressBar/index.ts @@ -1 +1 @@ -export * from './container/progressBar'; \ No newline at end of file +export * from './container/progressBar'; diff --git a/src/components/autoHeightImage/autoHeightImage.tsx b/src/components/autoHeightImage/autoHeightImage.tsx index 9596e79bf..e41f1917e 100644 --- a/src/components/autoHeightImage/autoHeightImage.tsx +++ b/src/components/autoHeightImage/autoHeightImage.tsx @@ -1,63 +1,59 @@ -import React, { useEffect, useState } from "react"; -import { Image } from "react-native"; -import EStyleSheet from "react-native-extended-stylesheet"; -import FastImage from "react-native-fast-image"; -import { TouchableOpacity } from "react-native-gesture-handler"; +import React, { useEffect, useState } from 'react'; +import { Image } from 'react-native'; +import EStyleSheet from 'react-native-extended-stylesheet'; +import FastImage from 'react-native-fast-image'; +import { TouchableOpacity } from 'react-native-gesture-handler'; - interface AutoHeightImageProps { - contentWidth:number, - imgUrl:string, - isAnchored:boolean, - activeOpacity?:number, - onPress:()=>void, - } +interface AutoHeightImageProps { + contentWidth: number; + imgUrl: string; + isAnchored: boolean; + activeOpacity?: number; + onPress: () => void; +} +export const AutoHeightImage = ({ + contentWidth, + imgUrl, + isAnchored, + activeOpacity, + onPress, +}: AutoHeightImageProps) => { + const [imgWidth, setImgWidth] = useState(contentWidth); + const [imgHeight, setImgHeight] = useState(imgWidth * (9 / 16)); + const [onLoadCalled, setOnLoadCalled] = useState(false); - export const AutoHeightImage = ({ - contentWidth, - imgUrl, - isAnchored, - activeOpacity, - onPress - }:AutoHeightImageProps) => { + useEffect(() => { + _fetchImageBounds(); + }, []); + const _fetchImageBounds = () => { + Image.getSize(imgUrl, (width, height) => { + const newWidth = width < contentWidth ? width : contentWidth; + const newHeight = (height / width) * newWidth; + setImgHeight(newHeight); + setImgWidth(newWidth); + }); + }; - const [imgWidth, setImgWidth] = useState(contentWidth); - const [imgHeight, setImgHeight] = useState(imgWidth * (9/16)) - const [onLoadCalled, setOnLoadCalled] = useState(false); + const imgStyle = { + width: imgWidth - 10, + height: imgHeight, + backgroundColor: onLoadCalled ? 'transparent' : EStyleSheet.value('$primaryGray'), + }; - useEffect(() => { - _fetchImageBounds(); - }, []) + const _onLoad = () => { + setOnLoadCalled(true); + }; - const _fetchImageBounds = () => { - Image.getSize(imgUrl, (width, height)=>{ - const newWidth = width < contentWidth ? width : contentWidth; - const newHeight = (height / width) * newWidth; - setImgHeight(newHeight); - setImgWidth(newWidth); - }) - } - - const imgStyle = { - width:imgWidth - 10, - height:imgHeight, - backgroundColor: onLoadCalled ? 'transparent' : EStyleSheet.value('$primaryGray') - } - - const _onLoad = () => { - setOnLoadCalled(true); - } - - return ( - - - - - ) - } \ No newline at end of file + return ( + + + + ); +}; diff --git a/src/components/basicHeader/container/basicHeaderContainer.tsx b/src/components/basicHeader/container/basicHeaderContainer.tsx index 43e0262c4..b26da3ab8 100644 --- a/src/components/basicHeader/container/basicHeaderContainer.tsx +++ b/src/components/basicHeader/container/basicHeaderContainer.tsx @@ -9,12 +9,11 @@ import { setHidePostsThumbnails } from '../../../redux/actions/applicationAction // Components import BasicHeaderView from '../view/basicHeaderView'; - interface BackHeaderProps { - backIconName:'close'|'arrow-back'; + backIconName: 'close' | 'arrow-back'; } -const BasicHeaderContainer = (props:BackHeaderProps) => { +const BasicHeaderContainer = (props: BackHeaderProps) => { const dispatch = useAppDispatch(); const isHideImages = useAppSelector((state) => state.application.hidePostsThumbnails); diff --git a/src/components/basicHeader/view/basicHeaderView.tsx b/src/components/basicHeader/view/basicHeaderView.tsx index 260848583..da98a13af 100644 --- a/src/components/basicHeader/view/basicHeaderView.tsx +++ b/src/components/basicHeader/view/basicHeaderView.tsx @@ -3,6 +3,7 @@ import { View, Text, ActivityIndicator, SafeAreaView } from 'react-native'; import { injectIntl } from 'react-intl'; // Components +import EStyleSheet from 'react-native-extended-stylesheet'; import { TextButton } from '../..'; import { IconButton } from '../../iconButton'; import { DropdownButton } from '../../dropdownButton'; @@ -12,7 +13,6 @@ import { TextInput } from '../../textInput'; // Styles import styles from './basicHeaderStyles'; import { OptionsModal } from '../../atoms'; -import EStyleSheet from 'react-native-extended-stylesheet'; const BasicHeaderView = ({ disabled, @@ -48,11 +48,9 @@ const BasicHeaderView = ({ handleSettingsPress, backIconName, }) => { - const [isInputVisible, setIsInputVisible] = useState(false); const rewardMenuRef = useRef(null); - /** * * ACTION HANDLERS @@ -79,7 +77,6 @@ const BasicHeaderView = ({ handleOnSearch(value); }; - const _handleRewardMenuSelect = (index) => { let rewardType = 'default'; @@ -99,8 +96,6 @@ const BasicHeaderView = ({ } }; - - /** * * UI RENDERER @@ -206,7 +201,10 @@ const BasicHeaderView = ({ onPress={() => handleOnSaveButtonPress && handleOnSaveButtonPress()} /> ) : ( - + )} )} @@ -229,13 +227,15 @@ const BasicHeaderView = ({ text={rightButtonText} /> ) : ( - + )} )} - - ); }; diff --git a/src/components/beneficiarySelectionContent/beneficiarySelectionContent.tsx b/src/components/beneficiarySelectionContent/beneficiarySelectionContent.tsx index a7277df66..3ee0210d6 100644 --- a/src/components/beneficiarySelectionContent/beneficiarySelectionContent.tsx +++ b/src/components/beneficiarySelectionContent/beneficiarySelectionContent.tsx @@ -3,11 +3,11 @@ import { View, FlatList, Text, TouchableOpacity } from 'react-native'; import { useIntl } from 'react-intl'; import { isArray, debounce } from 'lodash'; -import styles from './styles'; import EStyleSheet from 'react-native-extended-stylesheet'; +import styles from './styles'; import { useAppDispatch, useAppSelector } from '../../hooks'; -import { BeneficiaryModal, CheckBox, FormInput, IconButton, TextButton } from '../../components'; +import { BeneficiaryModal, CheckBox, FormInput, IconButton, TextButton } from '..'; import { Beneficiary } from '../../redux/reducers/editorReducer'; import { lookupAccounts } from '../../providers/hive/dhive'; import { TEMP_BENEFICIARIES_ID } from '../../redux/constants/constants'; @@ -17,12 +17,11 @@ import { } from '../../redux/actions/editorActions'; interface BeneficiarySelectionContentProps { - draftId: string; setDisableDone: (value: boolean) => void; powerDown?: boolean; - label?:string; - labelStyle?:string; + label?: string; + labelStyle?: string; powerDownBeneficiaries?: Beneficiary[]; handleSaveBeneficiary?: (beneficiaries: Beneficiary[]) => void; handleRemoveBeneficiary?: (beneficiary: Beneficiary) => void; @@ -38,7 +37,6 @@ const BeneficiarySelectionContent = ({ handleSaveBeneficiary, handleRemoveBeneficiary, }: BeneficiarySelectionContentProps) => { - const intl = useIntl(); const dispatch = useAppDispatch(); @@ -76,7 +74,7 @@ const BeneficiarySelectionContent = ({ const readPowerDownBeneficiaries = () => { const tempBeneficiaries = [ { account: username, weight: 10000, autoPowerUp: false }, - ...powerDownBeneficiaries as Beneficiary[], + ...(powerDownBeneficiaries as Beneficiary[]), ]; if (isArray(tempBeneficiaries) && tempBeneficiaries.length > 0) { @@ -96,8 +94,11 @@ const BeneficiarySelectionContent = ({ const readTempBeneficiaries = async () => { if (beneficiariesMap) { const savedBeneficiareis = beneficiariesMap[draftId || TEMP_BENEFICIARIES_ID]; - const tempBeneficiaries = savedBeneficiareis && savedBeneficiareis.length ? [DEFAULT_BENEFICIARY, ...beneficiariesMap[draftId || TEMP_BENEFICIARIES_ID]] : [DEFAULT_BENEFICIARY]; - + const tempBeneficiaries = + savedBeneficiareis && savedBeneficiareis.length + ? [DEFAULT_BENEFICIARY, ...beneficiariesMap[draftId || TEMP_BENEFICIARIES_ID]] + : [DEFAULT_BENEFICIARY]; + if (isArray(tempBeneficiaries) && tempBeneficiaries.length > 0) { //weight correction algorithm. let othersWeight = 0; @@ -242,7 +243,7 @@ const BeneficiarySelectionContent = ({ onChange={(value) => _onWeightInputChange(value)} selectTextOnFocus={true} autoFocus={true} - returnKeyType={'next'} + returnKeyType="next" keyboardType="numeric" /> @@ -315,7 +316,7 @@ const BeneficiarySelectionContent = ({ beneficiaries[0].weight = beneficiaries[0].weight + item.weight; const removedBeneficiary = beneficiaries.splice(index, 1); setBeneficiaries([...beneficiaries]); - if(handleRemoveBeneficiary){ + if (handleRemoveBeneficiary) { handleRemoveBeneficiary(removedBeneficiary[0]); return; } @@ -364,7 +365,9 @@ const BeneficiarySelectionContent = ({ return ( - {label || intl.formatMessage({ id: 'editor.beneficiaries' })} + + {label || intl.formatMessage({ id: 'editor.beneficiaries' })} + { - + descriptors, +}: BottomTabBarProps) => { const dispatch = useDispatch(); - useEffect(()=>{ - dispatch(updateActiveBottomTab(routes[index].name)) - },[index]) - - + useEffect(() => { + dispatch(updateActiveBottomTab(routes[index].name)); + }, [index]); const _jumpTo = (route, isFocused) => { - - if(route.name === ROUTES.TABBAR.POST_BUTTON){ - navigation.navigate(ROUTES.SCREENS.EDITOR, {key: 'editor_post'}) + if (route.name === ROUTES.TABBAR.POST_BUTTON) { + navigation.navigate(ROUTES.SCREENS.EDITOR, { key: 'editor_post' }); return; } - const event = navigation.emit({ type: 'tabPress', target: route.key, canPreventDefault: true, - }) + }); //TODO: also enable tap to scroll up feature if (!isFocused && !event.defaultPrevented) { @@ -54,48 +44,38 @@ const BottomTabBarView = ({ } }; - - const _tabButtons = routes.map((route, idx) => { - const {tabBarActiveTintColor, tabBarInactiveTintColor} = descriptors[route.key].options + const { tabBarActiveTintColor, tabBarInactiveTintColor } = descriptors[route.key].options; const isFocused = index == idx; - const iconColor = isFocused ? tabBarActiveTintColor : tabBarInactiveTintColor + const iconColor = isFocused ? tabBarActiveTintColor : tabBarInactiveTintColor; let _iconProps = { - iconType:"MaterialIcons", - style:{ padding: 15 }, - name:route.params.iconName, - color:iconColor, - size:scalePx(26), - } + iconType: 'MaterialIcons', + style: { padding: 15 }, + name: route.params.iconName, + color: iconColor, + size: scalePx(26), + }; - let _tabBarIcon = + let _tabBarIcon = ; switch (route.name) { case ROUTES.TABBAR.NOTIFICATION: - _tabBarIcon = () + _tabBarIcon = ; break; case ROUTES.TABBAR.POST_BUTTON: - _iconProps.iconType = "MaterialCommunityIcons" - _tabBarIcon = + _iconProps.iconType = 'MaterialCommunityIcons'; + _tabBarIcon = ; break; } return ( - _jumpTo(route, isFocused)}> - {_tabBarIcon} - + _jumpTo(route, isFocused)}>{_tabBarIcon} - ) - }) + ); + }); - - return ( - - {_tabButtons} - - ); + return {_tabButtons}; }; export default BottomTabBarView; diff --git a/src/components/comment/view/commentView.tsx b/src/components/comment/view/commentView.tsx index 00f9b9d88..ccf3dd8b8 100644 --- a/src/components/comment/view/commentView.tsx +++ b/src/components/comment/view/commentView.tsx @@ -4,6 +4,7 @@ import { useIntl } from 'react-intl'; import get from 'lodash/get'; import { View as AnimatedView } from 'react-native-animatable'; +import { useDispatch } from 'react-redux'; import { getTimeFromNow } from '../../../utils/time'; // Constants @@ -18,7 +19,6 @@ import { TextWithIcon } from '../../basicUIElements'; import styles from './commentStyles'; import { useAppSelector } from '../../../hooks'; import { OptionsModal } from '../../atoms'; -import { useDispatch } from 'react-redux'; import { showReplyModal } from '../../../redux/actions/uiAction'; import postTypes from '../../../constants/postTypes'; @@ -42,14 +42,16 @@ const CommentView = ({ hideManyCommentsButton, openReplyThread, fetchedAt, - incrementRepliesCount + incrementRepliesCount, }) => { const intl = useIntl(); const dispatch = useDispatch(); const actionSheet = useRef(null); const repliesContainerRef = useRef(null); - const isMuted = useAppSelector(state => state.account.currentAccount.mutes?.indexOf(comment.author) > -1); + const isMuted = useAppSelector( + (state) => state.account.currentAccount.mutes?.indexOf(comment.author) > -1, + ); const lastCacheUpdate = useAppSelector((state) => state.cache.lastUpdate); const cachedComments = useAppSelector((state) => state.cache.comments); @@ -61,17 +63,16 @@ const CommentView = ({ const [childCount, setChildCount] = useState(comment.children); const [replies, setReplies] = useState(comment.replies); - - useEffect(()=>{ - if(isShowSubComments){ - setTimeout(()=>{ - if(repliesContainerRef.current){ + useEffect(() => { + if (isShowSubComments) { + setTimeout(() => { + if (repliesContainerRef.current) { setIsShowSubComments(true); repliesContainerRef.current.slideInRight(300); } - },150) + }, 150); } - },[]) + }, []); useEffect(() => { if (comment) { @@ -79,7 +80,6 @@ const CommentView = ({ } }, [comment]); - useEffect(() => { const postPath = `${comment.author || ''}/${comment.permlink || ''}`; //this conditional makes sure on targetted already fetched post is updated @@ -107,11 +107,10 @@ const CommentView = ({ }, [lastCacheUpdate]); const _showSubCommentsToggle = (force) => { - if (((replies && replies.length > 0) || force)) { - + if ((replies && replies.length > 0) || force) { if (repliesContainerRef.current) { if (_isShowSubComments) { - repliesContainerRef.current.slideOutRight(300).then(()=>{ + repliesContainerRef.current.slideOutRight(300).then(() => { setIsShowSubComments(false); }); } else { @@ -119,233 +118,213 @@ const CommentView = ({ repliesContainerRef.current.slideInRight(300); } } - + setIsPressedShowButton(true); - - } else if (openReplyThread) { - openReplyThread(); - } - -}; - -const _handleCacheVoteIncrement = () => { - //fake increment vote using based on local change - setCacheVoteIcrement(1); -}; - -const _incrementRepliesCount = () => { - if (commentNumber > 1 && incrementRepliesCount) { - incrementRepliesCount(); - } - setChildCount(childCount + 1); -} - -const _handleOnReplyPress = () => { - if (isLoggedIn) { - dispatch(showReplyModal(comment)); - } else { - console.log('Not LoggedIn'); - } -} - -const _renderReadMoreButton = () => ( - openReplyThread && openReplyThread()} - text={ - !isPressedShowButton - ? intl.formatMessage({ id: 'comments.read_more' }) - : '' + } else if (openReplyThread) { + openReplyThread(); } - /> + }; -) + const _handleCacheVoteIncrement = () => { + //fake increment vote using based on local change + setCacheVoteIcrement(1); + }; -const _renderReplies = () => { + const _incrementRepliesCount = () => { + if (commentNumber > 1 && incrementRepliesCount) { + incrementRepliesCount(); + } + setChildCount(childCount + 1); + }; + const _handleOnReplyPress = () => { + if (isLoggedIn) { + dispatch(showReplyModal(comment)); + } else { + console.log('Not LoggedIn'); + } + }; - return ( - - {_isShowSubComments && - 0} - fetchPost={fetchPost} - hideManyCommentsButton={hideManyCommentsButton} - mainAuthor={mainAuthor} - fetchedAt={fetchedAt} - incrementRepliesCount={_incrementRepliesCount} - handleOnReplyPress={_handleOnReplyPress} - />} - + const _renderReadMoreButton = () => ( + openReplyThread && openReplyThread()} + text={!isPressedShowButton ? intl.formatMessage({ id: 'comments.read_more' }) : ''} + /> + ); - ) -} + const _renderReplies = () => { + return ( + + {_isShowSubComments && ( + 0} + fetchPost={fetchPost} + hideManyCommentsButton={hideManyCommentsButton} + mainAuthor={mainAuthor} + fetchedAt={fetchedAt} + incrementRepliesCount={_incrementRepliesCount} + handleOnReplyPress={_handleOnReplyPress} + /> + )} + + ); + }; - -const _renderComment = () => { - return (( - - - - - - {_renderActionPanel()} - - {commentNumber > 1 && - childCount > 0 && - !replies?.length && - _renderReadMoreButton() - } - - - )) -} - - -const _renderActionPanel = () => { - return ( - <> - - - handleOnVotersPress && - activeVotes.length > 0 && - handleOnVotersPress(activeVotes, comment) - } - text={activeVotes.length + cacheVoteIcrement} - textStyle={styles.voteCountText} - /> - - {isLoggedIn && ( - { + return ( + + - )} - - {currentAccountUsername === comment.author && ( + {_renderActionPanel()} + {commentNumber > 1 && childCount > 0 && !replies?.length && _renderReadMoreButton()} + + + ); + }; + + const _renderActionPanel = () => { + return ( + <> + + + handleOnVotersPress && + activeVotes.length > 0 && + handleOnVotersPress(activeVotes, comment) + } + text={activeVotes.length + cacheVoteIcrement} + textStyle={styles.voteCountText} + /> + + {isLoggedIn && ( handleOnEditPress && handleOnEditPress(comment)} - iconType="MaterialIcons" + name="comment-outline" + onPress={_handleOnReplyPress} + iconType="MaterialCommunityIcons" /> - {!childCount && !activeVotes.length && comment.isDeletable && ( - - actionSheet.current.show()} - iconType="MaterialIcons" - /> - { - index === 0 ? handleDeleteComment(comment.permlink) : null; - }} - /> - - )} - - )} + )} + {currentAccountUsername === comment.author && ( + + handleOnEditPress && handleOnEditPress(comment)} + iconType="MaterialIcons" + /> + {!childCount && !activeVotes.length && comment.isDeletable && ( + + actionSheet.current.show()} + iconType="MaterialIcons" + /> + { + index === 0 ? handleDeleteComment(comment.permlink) : null; + }} + /> + + )} + + )} - {commentNumber === 1 && childCount > 0 && ( - - _showSubCommentsToggle()} - text={`${childCount} ${intl.formatMessage({ id: 'comments.more_replies' })}`} - /> - - )} + {commentNumber === 1 && childCount > 0 && ( + + _showSubCommentsToggle()} + text={`${childCount} ${intl.formatMessage({ id: 'comments.more_replies' })}`} + /> + + )} + + ); + }; - - ) -} + const customContainerStyle = commentNumber > 2 ? { marginLeft: 44 } : null; -const customContainerStyle = commentNumber > 2 ? { marginLeft: 44 } : null + return ( + + + -return ( - - - - - {commentNumber > 0 && _renderReplies()} - - -); + {commentNumber > 0 && _renderReplies()} + + + ); }; export default CommentView; diff --git a/src/components/comments/view/commentsView.tsx b/src/components/comments/view/commentsView.tsx index 529153c84..8fc7d034f 100644 --- a/src/components/comments/view/commentsView.tsx +++ b/src/components/comments/view/commentsView.tsx @@ -4,14 +4,13 @@ import get from 'lodash/get'; import { useIntl } from 'react-intl'; // Components +import EStyleSheet from 'react-native-extended-stylesheet'; import { Comment, TextButton } from '../..'; // Styles import styles from './commentStyles'; -import EStyleSheet from 'react-native-extended-stylesheet'; import { OptionsModal } from '../../atoms'; - const CommentsView = ({ avatarSize, commentCount, @@ -36,13 +35,12 @@ const CommentsView = ({ flatListProps, openReplyThread, fetchedAt, - incrementRepliesCount + incrementRepliesCount, }) => { const [selectedComment, setSelectedComment] = useState(null); const intl = useIntl(); const commentMenu = useRef(); - const _openCommentMenu = (item) => { if (commentMenu.current) { setSelectedComment(item); @@ -52,21 +50,20 @@ const CommentsView = ({ const _openReplyThread = (item) => { if (item && openReplyThread) { - openReplyThread(item) + openReplyThread(item); } - - } + }; const _readMoreComments = () => { if (comments[0] && openReplyThread) { - openReplyThread(comments[0]) + openReplyThread(comments[0]); } }; const _onMenuItemPress = (index) => { - handleOnPressCommentMenu(index, selectedComment) + handleOnPressCommentMenu(index, selectedComment); setSelectedComment(null); - } + }; const menuItems = [ intl.formatMessage({ id: 'post.copy_link' }), @@ -75,7 +72,6 @@ const CommentsView = ({ intl.formatMessage({ id: 'alert.cancel' }), ]; - if (!hideManyCommentsButton && hasManyComments) { return ( { return ( - ) + ); }; - - const styleOerride = commentNumber > 1 ? { - backgroundColor: EStyleSheet.value('$primaryLightBackground'), - marginTop: 8, - } : null + const styleOerride = + commentNumber > 1 + ? { + backgroundColor: EStyleSheet.value('$primaryLightBackground'), + marginTop: 8, + } + : null; const _renderEmptyContent = () => { - if(commentNumber > 1){ + if (commentNumber > 1) { return; } const _onPress = () => { - handleOnReplyPress() - } + handleOnReplyPress(); + }; return ( - {intl.formatMessage({ id: "comments.no_comments" })} + {intl.formatMessage({ id: 'comments.no_comments' })} - ) - } - + ); + }; return ( diff --git a/src/components/commentsDisplay/view/writeCommentButton.tsx b/src/components/commentsDisplay/view/writeCommentButton.tsx index ad3ab42cb..a41815f46 100644 --- a/src/components/commentsDisplay/view/writeCommentButton.tsx +++ b/src/components/commentsDisplay/view/writeCommentButton.tsx @@ -1,57 +1,56 @@ -import { View, Text } from 'react-native' -import React, { forwardRef, useImperativeHandle, useRef } from 'react' -import UserAvatar from '../../userAvatar'; +import { View, Text } from 'react-native'; +import React, { forwardRef, useImperativeHandle, useRef } from 'react'; import { View as AnimatedView } from 'react-native-animatable'; import { TouchableOpacity } from 'react-native-gesture-handler'; +import { useIntl } from 'react-intl'; +import UserAvatar from '../../userAvatar'; import styles from './WriteCommentButtonStyles'; import { useAppSelector } from '../../../hooks'; import showLoginAlert from '../../../utils/showLoginAlert'; -import { useIntl } from 'react-intl'; interface WriteCommentButton { - onPress: () => void; + onPress: () => void; } export const WriteCommentButton = forwardRef(({ onPress }, ref) => { - const intl = useIntl(); + const intl = useIntl(); - const animatedContainer = useRef(); + const animatedContainer = useRef(); - 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 ( - - - - - - - {intl.formatMessage({id:'quick_reply.placeholder'})} - - - - - - - ) -}) + return ( + + + + + + + {intl.formatMessage({ id: 'quick_reply.placeholder' })} + + + + + + ); +}); diff --git a/src/components/customiseFiltersModal/customiseFiltersModalStyles.ts b/src/components/customiseFiltersModal/customiseFiltersModalStyles.ts index 22f1cbb95..5c7750023 100644 --- a/src/components/customiseFiltersModal/customiseFiltersModalStyles.ts +++ b/src/components/customiseFiltersModal/customiseFiltersModalStyles.ts @@ -3,91 +3,85 @@ import EStyleSheet from 'react-native-extended-stylesheet'; import getWindowDimensions from '../../utils/getWindowDimensions'; 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', - }, + sheetContent: { + backgroundColor: '$primaryBackgroundColor', + }, - container:{ - marginTop:16, - marginBottom:44, - paddingHorizontal:24, - alignItems:'center', - justifyContent:'space-between', - } as ViewStyle, + container: { + marginTop: 16, + marginBottom: 44, + paddingHorizontal: 24, + alignItems: 'center', + justifyContent: 'space-between', + } as ViewStyle, - imageStyle:{ - marginTop:8, - height:150, - width:150, - } as ImageStyle, + imageStyle: { + marginTop: 8, + height: 150, + width: 150, + } 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', + width: 150, + paddingVertical: 16, + borderRadius: 32, + justifyContent: 'center', + alignItems: 'center', + } as ViewStyle, - backgroundColor:'$primaryBlue', - width:150, - paddingVertical:16, - borderRadius:32, - justifyContent:'center', - alignItems:'center' - } as ViewStyle, + actionPanel: { + width: '100%', + flexDirection: 'row', + justifyContent: 'space-around', + alignItems: 'center', + } as ViewStyle, + checkView: { + width: getWindowDimensions().width - 80, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + marginHorizontal: 20, + marginVertical: 4, + } as ViewStyle, - actionPanel:{ - width:'100%', - flexDirection:'row', - justifyContent:'space-around', - alignItems:'center', - } as ViewStyle, - - checkView: { - width:getWindowDimensions().width - 80, - flexDirection: 'row', - justifyContent: 'space-between', - alignItems:'center', - marginHorizontal: 20, - marginVertical:4, - } as ViewStyle, - - - informationText: { - color: '$primaryBlack', - margin: 10, - fontSize:18, - } as TextStyle, - - - -}) \ No newline at end of file + informationText: { + color: '$primaryBlack', + margin: 10, + fontSize: 18, + } as TextStyle, +}); diff --git a/src/components/dropdownButton/view/dropdownButtonView.tsx b/src/components/dropdownButton/view/dropdownButtonView.tsx index e575f0636..824a255ab 100644 --- a/src/components/dropdownButton/view/dropdownButtonView.tsx +++ b/src/components/dropdownButton/view/dropdownButtonView.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { View, Text, ActivityIndicator, TouchableHighlight} from 'react-native'; +import { View, Text, ActivityIndicator, TouchableHighlight } from 'react-native'; import EStyleSheet from 'react-native-extended-stylesheet'; // External components import ModalDropdown from 'react-native-modal-dropdown'; @@ -25,28 +25,28 @@ const renderDropdownRow = ( noHighlight, dropdownRowWrapper, ) => ( - + - - {rowData} - - + {rowData} + + ); -const adjustDropdownFrame = (style:any) => { - style.left = 'auto' - style.right = 10 - return style -} +const adjustDropdownFrame = (style: any) => { + style.left = 'auto'; + style.right = 10; + return style; +}; const DropdownButtonView = ({ childIconWrapperStyle, children, @@ -72,7 +72,10 @@ const DropdownButtonView = ({ adjustDropdownFrame(style) } + adjustFrame={(style: any) => adjustDropdownFrame(style)} > {isHasChildIcon && !isLoading ? ( - - {defaultText} - + {defaultText} { const dispatch = useAppDispatch(); diff --git a/src/components/foregroundNotification/foregroundNotification.tsx b/src/components/foregroundNotification/foregroundNotification.tsx index ab3c2daa7..a6f022bde 100644 --- a/src/components/foregroundNotification/foregroundNotification.tsx +++ b/src/components/foregroundNotification/foregroundNotification.tsx @@ -3,6 +3,7 @@ import React, { useEffect, useRef, useState } from 'react'; import { Text, TouchableOpacity, View } from 'react-native'; import { View as AnimatedView } from 'react-native-animatable'; import { useDispatch } from 'react-redux'; +import { useIntl } from 'react-intl'; import { IconButton } from '..'; import { toastNotification } from '../../redux/actions/uiAction'; import UserAvatar from '../userAvatar'; @@ -11,7 +12,6 @@ import ROUTES from '../../constants/routeNames'; // Styles import styles, { CONTAINER_HEIGHT } from './styles'; import { navigate } from '../../navigation/service'; -import { useIntl } from 'react-intl'; interface RemoteMessage { data: { @@ -26,15 +26,13 @@ interface RemoteMessage { notification: { body: string; title: string; - } - + }; } interface Props { - remoteMessage: RemoteMessage + remoteMessage: RemoteMessage; } - const ForegroundNotification = ({ remoteMessage }: Props) => { const intl = useIntl(); @@ -48,26 +46,23 @@ const ForegroundNotification = ({ remoteMessage }: Props) => { const [title, setTitle] = useState(''); const [body, setBody] = useState(''); - useEffect(() => { - if (remoteMessage) { const { source, target, type, id } = remoteMessage.data; if (activeId !== id && (type === 'reply' || type === 'mention')) { - let titlePrefixId = ''; switch (type) { case 'reply': - titlePrefixId = 'notification.reply_on' + titlePrefixId = 'notification.reply_on'; break; case 'mention': - titlePrefixId = 'notification.mention_on' + titlePrefixId = 'notification.mention_on'; break; } setActiveId(id); setUsername(source); - setTitle(`${intl.formatMessage({ id: titlePrefixId })} @${target}`) + setTitle(`${intl.formatMessage({ id: titlePrefixId })} @${target}`); setBody(intl.formatMessage({ id: 'notification.reply_body' })); show(); } @@ -77,14 +72,14 @@ const ForegroundNotification = ({ remoteMessage }: Props) => { if (hideTimeoutRef.current) { clearTimeout(hideTimeoutRef.current); } - } + }; }, [remoteMessage]); const show = () => { - setIsVisible(true) + setIsVisible(true); hideTimeoutRef.current = setTimeout(() => { hide(); - }, duration) + }, duration); }; @@ -93,14 +88,12 @@ const ForegroundNotification = ({ remoteMessage }: Props) => { await containerRef.current.fadeOutUp(300); setIsVisible(false); - if(hideTimeoutRef.current){ + if (hideTimeoutRef.current){ clearTimeout(hideTimeoutRef.current); } - } }; - const _onPress = () => { const { data } = remoteMessage; const fullPermlink = @@ -110,7 +103,7 @@ const ForegroundNotification = ({ remoteMessage }: Props) => { author: get(data, 'source', ''), permlink: fullPermlink, }; - let key = fullPermlink + let key = fullPermlink; let routeName = ROUTES.SCREENS.POST; navigate({ @@ -119,41 +112,38 @@ const ForegroundNotification = ({ remoteMessage }: Props) => { key, }); hide(); - - } + }; return ( - isVisible && - + isVisible && ( + + + + + - - - - - - - - {title} - {body} + + + {title} + + + {body} + + - - - - - - - ) -} + + + + + ); + ); +}; export default ForegroundNotification; diff --git a/src/components/foregroundNotification/styles.ts b/src/components/foregroundNotification/styles.ts index bf5fe6308..764502272 100644 --- a/src/components/foregroundNotification/styles.ts +++ b/src/components/foregroundNotification/styles.ts @@ -5,16 +5,16 @@ import { getStatusBarHeight } from 'react-native-iphone-x-helper'; export const CONTAINER_HEIGHT = getStatusBarHeight() + 100; export default EStyleSheet.create({ - container:{ + container: { position: 'absolute', - top:0, - justifyContent:'center', + top: 0, + justifyContent: 'center', zIndex: 9999, - marginHorizontal:8, - paddingTop:16, + marginHorizontal: 8, + paddingTop: 16, marginTop: Platform.select({ - ios:getStatusBarHeight() + 12, - android:8, + ios: getStatusBarHeight() + 12, + android: 8, }), backgroundColor: '$darkGrayBackground', shadowColor: '#5f5f5fbf', @@ -23,20 +23,20 @@ export default EStyleSheet.create({ height: 5, }, elevation: 3, - borderRadius:12, + borderRadius: 12, width: '$deviceWidth - 16', }, - contentContainer:{ - flexDirection:'row', - justifyContent:'space-between', - alignItems:'center', - paddingBottom:16, - paddingHorizontal:16 + contentContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + paddingBottom: 16, + paddingHorizontal: 16, }, text: { color: 'white', fontWeight: 'bold', fontSize: 14, - paddingLeft:16, + paddingLeft: 16, }, }); diff --git a/src/components/formInput/view/formInputView.tsx b/src/components/formInput/view/formInputView.tsx index ee4bdd80d..2dece36b9 100644 --- a/src/components/formInput/view/formInputView.tsx +++ b/src/components/formInput/view/formInputView.tsx @@ -13,21 +13,20 @@ import { getResizedAvatar } from '../../../utils/image'; // Styles import styles from './formInputStyles'; - interface Props extends TextInputProps { - type:string; - isFirstImage:boolean; - isEditable?:boolean; - leftIconName?:string; - rightIconName?:string; - iconType?:string; - wrapperStyle:ViewStyle; - height:number; - inputStyle:TextStyle; - isValid:boolean; - onChange?:(value:string)=>void; - onFocus?:()=>void; - onBlur?:()=>void; + type: string; + isFirstImage: boolean; + isEditable?: boolean; + leftIconName?: string; + rightIconName?: string; + iconType?: string; + wrapperStyle: ViewStyle; + height: number; + inputStyle: TextStyle; + isValid: boolean; + onChange?: (value: string) => void; + onFocus?: () => void; + onBlur?: () => void; } const FormInputView = ({ @@ -48,7 +47,7 @@ const FormInputView = ({ onBlur, onFocus, ...props -}:Props) => { +}: Props) => { const [_value, setValue] = useState(value || ''); const [inputBorderColor, setInputBorderColor] = useState('#e7e7e7'); const [_isValid, setIsValid] = useState(true); @@ -65,7 +64,7 @@ const FormInputView = ({ const _handleOnFocus = () => { setInputBorderColor('#357ce6'); - if(onFocus){ + if (onFocus) { onFocus(); } }; diff --git a/src/components/header/view/headerView.tsx b/src/components/header/view/headerView.tsx index 46aac07c9..3d1881a37 100644 --- a/src/components/header/view/headerView.tsx +++ b/src/components/header/view/headerView.tsx @@ -46,13 +46,8 @@ const HeaderView = ({ }); }; - const _renderAvatar = () => ( - + - ) - + ); const _renderTitle = () => ( <> {displayName || username ? ( - {displayName && {displayName}} + {displayName && ( + + {displayName} + + )} {`@${username}`} {reputation && ` (${reputation})`} @@ -94,8 +92,7 @@ const HeaderView = ({ )} - ) - + ); const _renderActionButtons = () => ( <> @@ -123,11 +120,10 @@ const HeaderView = ({ )} - ) + ); return ( - {!hideUser && ( <> ({ showModal: async ({ selectedText, selection }) => { if (selectedText) { @@ -141,8 +134,8 @@ export const InsertLinkModal = forwardRef( setVisible(false)}// sheetModalRef.current?.setModalVisible(false)} - text={'Cancel'} + onPress={() => setVisible(false)} // sheetModalRef.current?.setModalVisible(false)} + text="Cancel" /> - {isLoading && } + {isLoading && } ); }; const _renderContent = ( - + {_renderInputs()} {_renderPreview()} {_renderFloatingPanel()} @@ -291,7 +284,6 @@ export const InsertLinkModal = forwardRef( ); return ( - {_renderContent} - ); }, ); diff --git a/src/components/insertLinkModal/insertLinkModalStyles.ts b/src/components/insertLinkModal/insertLinkModalStyles.ts index 59c15cc0f..b97e63541 100644 --- a/src/components/insertLinkModal/insertLinkModalStyles.ts +++ b/src/components/insertLinkModal/insertLinkModalStyles.ts @@ -19,7 +19,7 @@ export default EStyleSheet.create({ paddingTop: 32, paddingBottom: 16, }, - + container: { paddingVertical: 8, backgroundColor: '$primaryBackgroundColor', diff --git a/src/components/markdownEditor/children/editorToolbar.tsx b/src/components/markdownEditor/children/editorToolbar.tsx index 3f789bec2..f6ee483bb 100644 --- a/src/components/markdownEditor/children/editorToolbar.tsx +++ b/src/components/markdownEditor/children/editorToolbar.tsx @@ -1,26 +1,31 @@ -import { Keyboard, View, ViewStyle } from 'react-native' -import React, { useEffect, useMemo, useRef, useState } from 'react' -import { IconButton, UploadsGalleryModal } from '../..' -import { FlatList, HandlerStateChangeEvent, PanGestureHandler, PanGestureHandlerEventPayload } from 'react-native-gesture-handler'; +import { Keyboard, View, ViewStyle } from 'react-native'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; +import { + FlatList, + HandlerStateChangeEvent, + PanGestureHandler, + PanGestureHandlerEventPayload, +} from 'react-native-gesture-handler'; +import { getBottomSpace } from 'react-native-iphone-x-helper'; +import Animated, { Easing, Extrapolate } from 'react-native-reanimated'; +import { IconButton, UploadsGalleryModal } from '../..'; import styles from '../styles/editorToolbarStyles'; import { useAppSelector } from '../../../hooks'; import { MediaInsertData } from '../../uploadsGalleryModal/container/uploadsGalleryModal'; import Formats from './formats/formats'; -import { getBottomSpace } from 'react-native-iphone-x-helper'; -import Animated, { Easing, Extrapolate } from 'react-native-reanimated'; type Props = { - insertedMediaUrls: string[], - paramFiles: any[] - isEditing: boolean, - isPreviewActive: boolean, + insertedMediaUrls: string[]; + paramFiles: any[]; + isEditing: boolean; + isPreviewActive: boolean; setIsUploading: (isUploading: boolean) => void; handleMediaInsert: (data: MediaInsertData[]) => void; handleOnAddLinkPress: () => void; handleOnClearPress: () => void; handleOnMarkupButtonPress: (item) => void; handleShowSnippets: () => void; -} +}; export const EditorToolbar = ({ insertedMediaUrls, @@ -32,11 +37,9 @@ export const EditorToolbar = ({ handleOnAddLinkPress, handleOnClearPress, handleOnMarkupButtonPress, - handleShowSnippets - + handleShowSnippets, }: Props) => { - - const currentAccount = useAppSelector(state => state.account.currentAccount) + const currentAccount = useAppSelector((state) => state.account.currentAccount); const uploadsGalleryModalRef = useRef(null); const translateY = useRef(new Animated.Value(200)); const shouldHideExtension = useRef(false); @@ -47,18 +50,12 @@ export const EditorToolbar = ({ const [isKeyboardVisible, setKeyboardVisible] = useState(false); useEffect(() => { - const keyboardDidShowListener = Keyboard.addListener( - 'keyboardDidShow', - () => { - setKeyboardVisible(true); // or some other action - } - ); - const keyboardDidHideListener = Keyboard.addListener( - 'keyboardDidHide', - () => { - setKeyboardVisible(false); // or some other action - } - ); + const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => { + setKeyboardVisible(true); // or some other action + }); + const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => { + setKeyboardVisible(false); // or some other action + }); return () => { keyboardDidHideListener.remove(); @@ -74,7 +71,9 @@ export const EditorToolbar = ({ iconStyle={styles.icon} iconType={item.iconType} name={item.icon} - onPress={() => { handleOnMarkupButtonPress && handleOnMarkupButtonPress(item) }} + onPress={() => { + handleOnMarkupButtonPress && handleOnMarkupButtonPress(item); + }} /> ); @@ -86,8 +85,7 @@ export const EditorToolbar = ({ uploadsGalleryModalRef.current.toggleModal(true); _revealExtension(); } - } - + }; //handles extension closing const _onGestureEvent = Animated.event( @@ -99,30 +97,38 @@ export const EditorToolbar = ({ }, ], { - useNativeDriver: false - } + useNativeDriver: false, + }, ); - - const consY = useMemo(() => translateY.current.interpolate({ - inputRange: [0, 500], - outputRange: [0, 500], - extrapolate: Extrapolate.CLAMP - }), [translateY.current]); - + const consY = useMemo( + () => + translateY.current.interpolate({ + inputRange: [0, 500], + outputRange: [0, 500], + extrapolate: Extrapolate.CLAMP, + }), + [translateY.current], + ); const _animatedStyle = { transform: [ { translateY: consY, }, - ] - } + ], + }; const _onPanHandlerStateChange = (e: HandlerStateChangeEvent) => { - console.log("handler state change", e.nativeEvent.velocityY, e.nativeEvent.velocityY > 300, e.nativeEvent.translationY); - shouldHideExtension.current = e.nativeEvent.velocityY > 300 || e.nativeEvent.translationY > (extensionHeight.current / 2); - } + console.log( + 'handler state change', + e.nativeEvent.velocityY, + e.nativeEvent.velocityY > 300, + e.nativeEvent.translationY, + ); + shouldHideExtension.current = + e.nativeEvent.velocityY > 300 || e.nativeEvent.translationY > extensionHeight.current / 2; + }; const _revealExtension = () => { if (!isExtensionVisible) { @@ -135,9 +141,8 @@ export const EditorToolbar = ({ duration: 200, toValue: 0, easing: Easing.inOut(Easing.ease), - }).start() - } - + }).start(); + }; const _hideExtension = () => { Animated.timing(translateY.current, { @@ -151,29 +156,31 @@ export const EditorToolbar = ({ uploadsGalleryModalRef.current.toggleModal(false); } }); - } - + }; const _onPanEnded = () => { if (shouldHideExtension.current) { - _hideExtension() + _hideExtension(); } else { _revealExtension(); } - } - + }; const _renderExtension = () => { return ( - - - { - extensionHeight.current = e.nativeEvent.layout.height; - console.log('extension height', extensionHeight.current) - - }} style={styles.dropShadow}> + onEnded={_onPanEnded} + > + + { + extensionHeight.current = e.nativeEvent.layout.height; + console.log('extension height', extensionHeight.current); + }} + style={styles.dropShadow} + > {isExtensionVisible && } + setIsUploading={setIsUploading} + /> - ) - } + ); + }; - const _containerStyle: ViewStyle = isExtensionVisible ? styles.container : styles.shadowedContainer; + const _containerStyle: ViewStyle = isExtensionVisible + ? styles.container + : styles.shadowedContainer; const _buttonsContainerStyle: ViewStyle = { ...styles.buttonsContainer, borderTopWidth: isExtensionVisible ? 1 : 0, - paddingBottom: !isKeyboardVisible ? getBottomSpace() : 0 - } + paddingBottom: !isKeyboardVisible ? getBottomSpace() : 0, + }; return ( - {_renderExtension()} {!isPreviewActive && ( @@ -220,10 +229,14 @@ export const EditorToolbar = ({ iconStyle={styles.icon} iconType="FontAwesome" name="link" - onPress={() => { handleOnAddLinkPress && handleOnAddLinkPress() }} + onPress={() => { + handleOnAddLinkPress && handleOnAddLinkPress(); + }} /> { handleShowSnippets && handleShowSnippets() }} + onPress={() => { + handleShowSnippets && handleShowSnippets(); + }} style={styles.rightIcons} size={20} iconStyle={styles.icon} @@ -240,7 +253,9 @@ export const EditorToolbar = ({ /> { handleOnClearPress && handleOnClearPress() }} + onPress={() => { + handleOnClearPress && handleOnClearPress(); + }} size={20} iconStyle={styles.clearIcon} iconType="FontAwesome" @@ -251,9 +266,6 @@ export const EditorToolbar = ({ )} - - - - ) -} \ No newline at end of file + ); +}; diff --git a/src/components/markdownEditor/children/formats/applyMediaLink.ts b/src/components/markdownEditor/children/formats/applyMediaLink.ts index 3f7d5ea65..7c8c789e2 100644 --- a/src/components/markdownEditor/children/formats/applyMediaLink.ts +++ b/src/components/markdownEditor/children/formats/applyMediaLink.ts @@ -1,108 +1,102 @@ -import { MediaInsertData, MediaInsertStatus } from '../../../uploadsGalleryModal/container/uploadsGalleryModal'; +import { + MediaInsertData, + MediaInsertStatus, +} from '../../../uploadsGalleryModal/container/uploadsGalleryModal'; import { replaceBetween } from './utils'; interface Selection { - start: number, - end: number + start: number; + end: number; } interface Args { - text: string; - selection: Selection; - setTextAndSelection: ({ selection: Selection, text: string }) => void, - items: MediaInsertData[] + text: string; + selection: Selection; + setTextAndSelection: ({ selection: Selection, text: string }) => void; + items: MediaInsertData[]; } export default async ({ text, selection, setTextAndSelection, items }: Args) => { + //TODO: check if placeholder already present in text body + // check if cursor position is after or before media position + // replace placeholder with url or failure message + // calclulate change of cursor position - //TODO: check if placeholder already present in text body - // check if cursor position is after or before media position - // replace placeholder with url or failure message - // calclulate change of cursor position + const imagePrefix = '!'; + const placeholderPrefix = 'Uploading... '; - const imagePrefix = '!'; - const placeholderPrefix = 'Uploading... ' + let newText = text; + let newSelection = selection; - let newText = text; - let newSelection = selection; + const _insertFormatedString = (text, value) => { + const formatedText = `\n${imagePrefix}[${text}](${value})\n`; + newText = replaceBetween(newText, newSelection, formatedText); + const newIndex = newText && newText.indexOf(value, newSelection.start) + value.length + 2; + newSelection = { + start: newIndex, + end: newIndex, + }; + }; + const _replaceFormatedString = (placeholder: string, url: string) => { + const replaceStr = `(${placeholder})`; - const _insertFormatedString = (text, value) => { - const formatedText = `\n${imagePrefix}[${text}](${value})\n`; - newText = replaceBetween(newText, newSelection, formatedText); - const newIndex = newText && newText.indexOf(value, newSelection.start) + value.length + 2; - newSelection = { - start: newIndex, - end: newIndex - } + const endingIndex = newText.indexOf(replaceStr) + replaceStr.length + 1; + newText = newText.replace(replaceStr, `(${url})`); + + if (newSelection.start >= endingIndex) { + const lengthDiff = url.length - placeholder.length; + newSelection = { + start: newSelection.start + lengthDiff, + end: newSelection.end + lengthDiff, + }; } + }; + const _removeFormatedString = (placeholder) => { + const formatedText = `${imagePrefix}[](${placeholder})`; + const formatedTextIndex = newText.indexOf(formatedText); + newText = newText.replace(formatedText, ''); - const _replaceFormatedString = (placeholder: string, url: string) => { - const replaceStr = `(${placeholder})`; - - const endingIndex = newText.indexOf(replaceStr) + replaceStr.length + 1; - newText = newText.replace(replaceStr, `(${url})`); - - if (newSelection.start >= endingIndex) { - const lengthDiff = url.length - placeholder.length - newSelection = { - start: newSelection.start + lengthDiff, - end: newSelection.end + lengthDiff - } - } + if (newSelection.start > formatedTextIndex) { + newSelection = { + start: newSelection.start - formatedText.length, + end: newSelection.end - formatedText.length, + }; } + }; + items.forEach((item) => { + const _placeholder = item.filename && `${placeholderPrefix}${item.filename}`; - const _removeFormatedString = (placeholder) => { - const formatedText = `${imagePrefix}[](${placeholder})` - const formatedTextIndex = newText.indexOf(formatedText); - newText = newText.replace(formatedText, '') + switch (item.status) { + case MediaInsertStatus.UPLOADING: //means only filename is available + if (!_placeholder) return; + _insertFormatedString(item.text, _placeholder); + break; - if (newSelection.start > formatedTextIndex) { - newSelection = { - start: newSelection.start - formatedText.length, - end: newSelection.end - formatedText.length - } + case MediaInsertStatus.READY: //means url is ready but filename may be available + if (_placeholder && newText.includes(_placeholder)) { + //means placeholder is preset is needs replacing + _replaceFormatedString(_placeholder, item.url); + } else if (item.url) { + _insertFormatedString(item.text, item.url); } + break; + + case MediaInsertStatus.FAILED: //filename available but upload failed + if (_placeholder && newText.includes(_placeholder)) { + _removeFormatedString(_placeholder); + } + break; + + default: + if (item.url) { + _insertFormatedString(item.text, item.url); + } + break; } + }); - - - items.forEach(item => { - - const _placeholder = item.filename && `${placeholderPrefix}${item.filename}`; - - switch (item.status) { - case MediaInsertStatus.UPLOADING: //means only filename is available - if (!_placeholder) return; - _insertFormatedString(item.text, _placeholder) - break; - - case MediaInsertStatus.READY: //means url is ready but filename may be available - if (_placeholder && newText.includes(_placeholder)) { - //means placeholder is preset is needs replacing - _replaceFormatedString(_placeholder, item.url); - } else if (item.url) { - _insertFormatedString(item.text, item.url); - } - break; - - case MediaInsertStatus.FAILED: //filename available but upload failed - if (_placeholder && newText.includes(_placeholder)) { - _removeFormatedString(_placeholder); - } - break; - - default: - if (item.url) { - _insertFormatedString(item.text, item.url); - } - break; - } - - }); - - - setTextAndSelection({ text: newText, selection: newSelection }); + setTextAndSelection({ text: newText, selection: newSelection }); }; diff --git a/src/components/markdownEditor/children/formats/applySnippet.ts b/src/components/markdownEditor/children/formats/applySnippet.ts index b675b96cd..faca92ee1 100644 --- a/src/components/markdownEditor/children/formats/applySnippet.ts +++ b/src/components/markdownEditor/children/formats/applySnippet.ts @@ -1,10 +1,10 @@ -import {replaceBetween } from './utils'; +import { replaceBetween } from './utils'; -export default async ({ text, selection, setTextAndSelection, snippetText}) => { +export default async ({ text, selection, setTextAndSelection, snippetText }) => { const newText = replaceBetween(text, selection, `${snippetText}`); - const newSelection = { - start: selection.start, - end: selection.start + (snippetText && snippetText.length), - }; + const newSelection = { + start: selection.start, + end: selection.start + (snippetText && snippetText.length), + }; setTextAndSelection({ text: newText, selection: newSelection }); -}; \ No newline at end of file +}; diff --git a/src/components/markdownEditor/children/formats/applyUsername.ts b/src/components/markdownEditor/children/formats/applyUsername.ts index 9ff3454b1..7f986ad41 100644 --- a/src/components/markdownEditor/children/formats/applyUsername.ts +++ b/src/components/markdownEditor/children/formats/applyUsername.ts @@ -1,11 +1,15 @@ import { extractWordAtIndex } from '../../../../utils/editor'; -import {replaceBetween } from './utils'; +import { replaceBetween } from './utils'; -export default async ({ text, selection, setTextAndSelection, username}) => { - const _word = extractWordAtIndex(text, selection.start); - const _insertAt = text.indexOf(_word, selection.start - _word.length); - const _text = replaceBetween(text, {start:_insertAt, end:_insertAt + _word.length}, `@${username} `) - const _newPos = _insertAt + username.length + 2; - const _selection = { start: _newPos, end: _newPos }; - setTextAndSelection({ selection: _selection, text: _text }); -}; \ No newline at end of file +export default async ({ text, selection, setTextAndSelection, username }) => { + const _word = extractWordAtIndex(text, selection.start); + const _insertAt = text.indexOf(_word, selection.start - _word.length); + const _text = replaceBetween( + text, + { start: _insertAt, end: _insertAt + _word.length }, + `@${username} `, + ); + const _newPos = _insertAt + username.length + 2; + const _selection = { start: _newPos, end: _newPos }; + setTextAndSelection({ selection: _selection, text: _text }); +}; diff --git a/src/components/markdownEditor/children/usernameAutofillBar.tsx b/src/components/markdownEditor/children/usernameAutofillBar.tsx index ec66bae4c..ee8bf9b02 100644 --- a/src/components/markdownEditor/children/usernameAutofillBar.tsx +++ b/src/components/markdownEditor/children/usernameAutofillBar.tsx @@ -1,93 +1,104 @@ -import React, {useState, useEffect, useCallback} from 'react'; -import { View, FlatList, Text, TouchableOpacity } from "react-native" +import React, { useState, useEffect, useCallback } from 'react'; +import { View, FlatList, Text, TouchableOpacity } from 'react-native'; +import {debounce} from 'lodash'; import { UserAvatar } from '../..'; import { lookupAccounts } from '../../../providers/hive/dhive'; import { extractWordAtIndex } from '../../../utils/editor'; import styles from '../styles/markdownEditorStyles'; -import {debounce} from 'lodash'; interface Props { - text:string, - selection:{ - start:number, - end:number - } - onApplyUsername:(username:string)=>void; + text: string; + selection: { + start: number; + end: number; + }; + onApplyUsername: (username: string) => void; } -export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) => { +export const UsernameAutofillBar = ({ text, selection, onApplyUsername }: Props) => { + const [searchedUsers, setSearchedUsers] = useState([]); + const [query, setQuery] = useState(''); - const [searchedUsers, setSearchedUsers] = useState([]) - const [query, setQuery] = useState(''); + useEffect(() => { + if (selection.start === selection.end && text) { + _processTextForSearch(text, selection.start); + } + }, [text, selection]); - useEffect(() => { - if (selection.start === selection.end && text) { - _processTextForSearch(text, selection.start); - } - }, [text, selection]) - - - const _processTextForSearch = useCallback(debounce((text:string, index:number) => { - const word = extractWordAtIndex(text, index); - console.log('selection word is: ', word); - if (word.startsWith('@') && word.length > 1) { - _handleUserSearch(word.substring(1)); - } else { - setSearchedUsers([]); - setQuery('') - _handleUserSearch.cancel(); - } - }, 300, {leading:true}),[]); - - - const _handleUserSearch = useCallback(debounce(async (username) => { - if(query !== username){ - let users = []; - if (username) { - setQuery(username) - users = await lookupAccounts(username); - console.log('result users for', username, users); + const _processTextForSearch = useCallback( + debounce( + (text: string, index: number) => { + const word = extractWordAtIndex(text, index); + console.log('selection word is: ', word); + if (word.startsWith('@') && word.length > 1) { + _handleUserSearch(word.substring(1)); + } else { + setSearchedUsers([]); + setQuery(''); + _handleUserSearch.cancel(); } - setSearchedUsers(users); - } - - }, 200, {leading:true}), []); + }, + 300, + { leading: true }, + ), + [], + ); + const _handleUserSearch = useCallback( + debounce( + async (username) => { + if (query !== username) { + let users = []; + if (username) { + setQuery(username); + users = await lookupAccounts(username); + console.log('result users for', username, users); + } + setSearchedUsers(users); + } - - const _onUserSelect = (username) => { - onApplyUsername(username) - setSearchedUsers([]); - setQuery('') - }; + 200, + { leading: true }, + ), - if(!searchedUsers || searchedUsers.length === 0 || query === ''){ - return null; - } + ); - const _renderItem = ({item}:{item:string}) => { + const _onUserSelect = (username) => { + onApplyUsername(username); + setSearchedUsers([]); + setQuery(''); + }; - const username = item; - return ( - {_onUserSelect(username)}}> - - - {username} - - - ) - } - - return ( - - `searched-user-${item}`} - /> - - ) + if (!searchedUsers || searchedUsers.length === 0 || query === '') { + return null; } + + const _renderItem = ({ item }: { item: string }) => { + const username = item; + return ( + { + _onUserSelect(username); + }} + > + + + {username} + + + ); + }; + + return ( + + `searched-user-${item}`} + /> + + ); +}; diff --git a/src/components/markdownEditor/styles/editorToolbarStyles.ts b/src/components/markdownEditor/styles/editorToolbarStyles.ts index f03dc5b7e..27edd485f 100644 --- a/src/components/markdownEditor/styles/editorToolbarStyles.ts +++ b/src/components/markdownEditor/styles/editorToolbarStyles.ts @@ -10,11 +10,11 @@ const _dropShadow = { }, backgroundColor: '$primaryBackgroundColor', borderColor: '$primaryLightBackground', - borderTopWidth : Platform.select({ + borderTopWidth: Platform.select({ android: 1, - ios: 0 - }) -} + ios: 0, + }), +}; export default EStyleSheet.create({ container: { @@ -22,13 +22,13 @@ export default EStyleSheet.create({ elevation: 3, backgroundColor: '$primaryBackgroundColor', }, - shadowedContainer:{ + shadowedContainer: { elevation: 3, width: '$deviceWidth', - ..._dropShadow + ..._dropShadow, }, dropShadow: { - ..._dropShadow + ..._dropShadow, }, buttonsContainer: { justifyContent: 'space-between', @@ -36,7 +36,7 @@ export default EStyleSheet.create({ width: '$deviceWidth', backgroundColor: '$primaryBackgroundColor', borderColor: '$primaryLightBackground', - paddingBottom: getBottomSpace() + paddingBottom: getBottomSpace(), }, clearIcon: { color: '$primaryLightGray', @@ -75,8 +75,6 @@ export default EStyleSheet.create({ backgroundColor: '$primaryLightBackground', borderRadius: 8, margin: 8, - alignSelf: 'center' - } + alignSelf: 'center', + }, }); - - diff --git a/src/components/markdownEditor/view/markdownEditorView.tsx b/src/components/markdownEditor/view/markdownEditorView.tsx index 82bf71cdf..f620fafee 100644 --- a/src/components/markdownEditor/view/markdownEditorView.tsx +++ b/src/components/markdownEditor/view/markdownEditorView.tsx @@ -50,7 +50,7 @@ import { useAppSelector } from '../../../hooks'; const MIN_BODY_INPUT_HEIGHT = 300; -//These variable keep track of body text input state, +//These variable keep track of body text input state, //this helps keep load on minimal compared to both useState and useRef; var bodyText = ''; var bodySelection = { start: 0, end: 0 }; @@ -74,11 +74,11 @@ const MarkdownEditorView = ({ autoFocusText, sharedSnippetText, onLoadDraftPress, - setIsUploading + setIsUploading, }) => { const dispatch = useDispatch(); - const isDarkTheme = useAppSelector(state => state.application.isDarkTheme); + const isDarkTheme = useAppSelector((state) => state.application.isDarkTheme); const [editable, setEditable] = useState(true); const [bodyInputHeight, setBodyInputHeight] = useState(MIN_BODY_INPUT_HEIGHT); @@ -87,7 +87,6 @@ const MarkdownEditorView = ({ const [isEditing, setIsEditing] = useState(false); const [insertedMediaUrls, setInsertedMediaUrls] = useState([]); - const inputRef = useRef(null); const clearRef = useRef(null); const insertLinkModalRef = useRef(null); @@ -164,7 +163,6 @@ const MarkdownEditorView = ({ } }, [isLoading]); - useEffect(() => { bodyText = draftBody; }, [draftBody]); @@ -178,8 +176,6 @@ const MarkdownEditorView = ({ } }, [autoFocusText]); - - const changeUser = async () => { dispatch(toggleAccountsBottomSheet(!isVisibleAccountsBottomSheet)); }; @@ -193,33 +189,37 @@ const MarkdownEditorView = ({ }); }; - - const _debouncedOnTextChange = useCallback(debounce(() => { - console.log("setting is editing to", false) - setIsEditing(false) - const urls = extractImageUrls({ body: bodyText }) - if (urls.length !== insertedMediaUrls.length) { - setInsertedMediaUrls(urls); - } - }, 500), []) + const _debouncedOnTextChange = useCallback( + debounce(() => { + console.log('setting is editing to', false); + setIsEditing(false); + const urls = extractImageUrls({ body: bodyText }); + if (urls.length !== insertedMediaUrls.length) { + setInsertedMediaUrls(urls); + } + }, 500), + [], + ); // eslint-disable-next-line react-hooks/exhaustive-deps - const _changeText = useCallback((input) => { - bodyText = input; + const _changeText = useCallback( + (input) => { + bodyText = input; - if (!isEditing) { - console.log('force setting is editing to true', true) - setIsEditing(true) - } + if (!isEditing) { + console.log('force setting is editing to true', true); + setIsEditing(true); + } - _debouncedOnTextChange(); - - //NOTE: onChange method is called by direct parent of MarkdownEditor that is PostForm, do not remove - if (onChange) { - onChange(input); - } - }, [isEditing]); + _debouncedOnTextChange(); + //NOTE: onChange method is called by direct parent of MarkdownEditor that is PostForm, do not remove + if (onChange) { + onChange(input); + } + }, + [isEditing], + ); const _handleOnSelectionChange = async (event) => { bodySelection = event.nativeEvent.selection; @@ -233,11 +233,11 @@ const MarkdownEditorView = ({ }); const _updateSelection = () => { - bodySelection = _selection + bodySelection = _selection; inputRef?.current?.setNativeProps({ selection: _selection, }); - } + }; // Workaround for iOS selection update issue if (Platform.OS === 'ios') { @@ -245,7 +245,7 @@ const MarkdownEditorView = ({ _updateSelection(); }, 100); } else { - _updateSelection() + _updateSelection(); } if (isSnippetsOpen) { @@ -275,8 +275,6 @@ const MarkdownEditorView = ({ setIsSnippetsOpen(false); }; - - const _handleMediaInsert = (mediaArray: MediaInsertData[]) => { if (mediaArray.length) { applyMediaLink({ @@ -288,9 +286,6 @@ const MarkdownEditorView = ({ } }; - - - const _handleOnAddLinkPress = () => { insertLinkModalRef.current?.showModal({ selectedText: bodyText.slice(bodySelection.start, bodySelection.end), @@ -314,7 +309,6 @@ const MarkdownEditorView = ({ insertLinkModalRef.current?.hideModal(); }; - const _renderFloatingDraftButton = () => { if (showDraftLoadButton) { const _onPress = () => { @@ -354,7 +348,7 @@ const MarkdownEditorView = ({ _setTextAndSelection({ text: '', selection: { start: 0, end: 0 } }); } }; - const _renderEditor = (editorScrollEnabled:boolean) => ( + const _renderEditor = (editorScrollEnabled: boolean) => ( <> {isReply && !isEdit && } {!isReply && ( @@ -397,38 +391,44 @@ const MarkdownEditorView = ({ )} {!isPreviewActive ? ( - + ) : ( _renderPreview() )} ); - const _editorWithScroll = {_renderEditor(false)}; + const _editorWithScroll = ( + {_renderEditor(false)} + ); const _editorWithoutScroll = {_renderEditor(true)}; const _renderContent = () => { const _innerContent = ( <> {isAndroidOreo() ? _editorWithoutScroll : _editorWithScroll} - + {_renderFloatingDraftButton()} - ); @@ -480,8 +479,6 @@ const MarkdownEditorView = ({ - - void; - children?: any + children?: any; } export const InputSupportModal = ({ children, visible, onClose }: InputSupportModalProps, ref) => { - const container = useRef(null); const innerContainer = useRef(null); @@ -20,48 +19,38 @@ export const InputSupportModal = ({ children, visible, onClose }: InputSupportMo useEffect(() => { if (visible) { setShowModal(true); - } - else if (!visible && container.current && innerContainer.current) { - innerContainer.current.slideOutDown(1000) + } else if (!visible && container.current && innerContainer.current) { + innerContainer.current.slideOutDown(1000); setTimeout(async () => { - await container.current?.fadeOut(200) + await container.current?.fadeOut(200); setShowModal(false); - }, 300) + }, 300); } - }, [visible]) + }, [visible]); - - return showModal && ( - - - - - - - + + + animation="slideInUp" + duration={300} + > + - { - Platform.select({ + {Platform.select({ ios: ( {children} ), android: {children}, - }) - } + })} + - - + + ) ); }; diff --git a/src/components/organisms/inputSupportModal/index.ts b/src/components/organisms/inputSupportModal/index.ts index fcb03ddfa..5b9d950cd 100644 --- a/src/components/organisms/inputSupportModal/index.ts +++ b/src/components/organisms/inputSupportModal/index.ts @@ -1 +1 @@ -export * from './container/inputSupportModal'; \ No newline at end of file +export * from './container/inputSupportModal'; diff --git a/src/components/postDropdown/container/postDropdownContainer.tsx b/src/components/postDropdown/container/postDropdownContainer.tsx index 318e80a10..87e173f33 100644 --- a/src/components/postDropdown/container/postDropdownContainer.tsx +++ b/src/components/postDropdown/container/postDropdownContainer.tsx @@ -82,11 +82,11 @@ class PostDropdownContainer extends PureComponent { const _canUpdateCommunityPin = subscribedCommunities.data && !!content && content.community ? subscribedCommunities.data.reduce((role, subscription) => { - if (content.community === subscription[0]) { - return ['owner', 'admin', 'mod'].includes(subscription[2]); - } - return role; - }, false) + if (content.community === subscription[0]) { + return ['owner', 'admin', 'mod'].includes(subscription[2]); + } + return role; + }, false) : false; const _isPinnedInCommunity = !!content && content.stats?.is_pinned; @@ -290,7 +290,7 @@ class PostDropdownContainer extends PureComponent { buttons: [ { text: intl.formatMessage({ id: 'alert.cancel' }), - onPress: () => { }, + onPress: () => {}, }, { text: intl.formatMessage({ id: 'alert.confirm' }), @@ -329,17 +329,16 @@ class PostDropdownContainer extends PureComponent { }; _reblog = () => { - const { - content, - currentAccount, - dispatch, - intl, - isLoggedIn, - pinCode, + const { + content, + currentAccount, + dispatch, + intl, + isLoggedIn, + pinCode, navigation, - userActivityMutation - } = this - .props as any; + userActivityMutation, + } = this.props as any; if (!isLoggedIn) { showLoginAlert({ navigation, intl }); return; @@ -349,9 +348,9 @@ class PostDropdownContainer extends PureComponent { .then((response) => { //track user activity points ty=130 userActivityMutation.mutate({ - pointsTy:PointActivityIds.REBLOG, - transactionId:response.id - }) + pointsTy: PointActivityIds.REBLOG, + transactionId: response.id, + }); dispatch( toastNotification( @@ -517,9 +516,11 @@ const mapStateToProps = (state) => ({ }); const mapQueriesToProps = () => ({ - userActivityMutation: useUserActivityMutation() -}) + userActivityMutation: useUserActivityMutation(), +}); -export default withNavigation(connect(mapStateToProps)(injectIntl((props) => ( - ))) +export default withNavigation( + connect(mapStateToProps)( + injectIntl((props) => ), + ), ); diff --git a/src/components/postElements/body/view/commentBodyView.tsx b/src/components/postElements/body/view/commentBodyView.tsx index e3da7c41b..cf01c36ec 100644 --- a/src/components/postElements/body/view/commentBodyView.tsx +++ b/src/components/postElements/body/view/commentBodyView.tsx @@ -1,4 +1,4 @@ -import React, { Fragment, useState, useRef } from 'react'; +import React, { Fragment, useState, useRef, useCallback } from 'react'; import { Linking, Modal, PermissionsAndroid, Platform, View } from 'react-native'; import { useIntl } from 'react-intl'; import CameraRoll from '@react-native-community/cameraroll'; @@ -8,6 +8,7 @@ import ActionsSheetView from 'react-native-actions-sheet'; // import AutoHeightWebView from 'react-native-autoheight-webview'; import EStyleSheet from 'react-native-extended-stylesheet'; +import { LongPressGestureHandler, State } from 'react-native-gesture-handler'; import { navigate } from '../../../../navigation/service'; // Constants @@ -21,8 +22,7 @@ import styles from './commentBodyStyles'; // Services and Actions import { writeToClipboard } from '../../../../utils/clipboard'; import { toastNotification } from '../../../../redux/actions/uiAction'; -import { LongPressGestureHandler, State } from 'react-native-gesture-handler'; -import { useCallback } from 'react'; + import { OptionsModal } from '../../../atoms'; import { useAppDispatch } from '../../../../hooks'; import { isCommunity } from '../../../../utils/communityValidation'; @@ -39,10 +39,9 @@ const CommentBody = ({ created, commentDepth, reputation = 25, - isMuted + isMuted, }) => { - - const _contentWidth = WIDTH - (40 + 28 + (commentDepth > 2 ? 44 : 0)) + const _contentWidth = WIDTH - (40 + 28 + (commentDepth > 2 ? 44 : 0)); const dispatch = useAppDispatch(); @@ -52,7 +51,7 @@ const CommentBody = ({ const [selectedLink, setSelectedLink] = useState(null); const [revealComment, setRevealComment] = useState(reputation > 0 && !isMuted); const [videoUrl, setVideoUrl] = useState(null); - const [youtubeVideoId, setYoutubeVideoId] = useState(null) + const [youtubeVideoId, setYoutubeVideoId] = useState(null); const [videoStartTime, setVideoStartTime] = useState(0); const intl = useIntl(); @@ -60,18 +59,16 @@ const CommentBody = ({ const actionLink = useRef(null); const youtubePlayerRef = useRef(null); - - const _onLongPressStateChange = ({nativeEvent}) => { - if(nativeEvent.state === State.ACTIVE){ + const _onLongPressStateChange = ({ nativeEvent }) => { + if (nativeEvent.state === State.ACTIVE) { handleOnLongPress(); } - } + }; const _showLowComment = () => { setRevealComment(true); }; - const handleImagePress = (ind) => { if (ind === 1) { //open gallery mode @@ -128,12 +125,11 @@ const CommentBody = ({ ); }); } - + setSelectedLink(null); - }; - const _handleTagPress = (tag:string, filter:string = GLOBAL_POST_FILTERS_VALUE[0]) => { + const _handleTagPress = (tag: string, filter: string = GLOBAL_POST_FILTERS_VALUE[0]) => { if (tag) { const routeName = isCommunity(tag) ? ROUTES.SCREENS.COMMUNITY : ROUTES.SCREENS.TAG_RESULT; const key = `${filter}/${tag}`; @@ -148,21 +144,21 @@ const CommentBody = ({ } }; - const _handleSetSelectedLink = (link:string) => { - setSelectedLink(link) + const _handleSetSelectedLink = (link: string) => { + setSelectedLink(link); actionLink.current.show(); - } + }; - const _handleSetSelectedImage = (imageLink:string, postImgUrls:string[]) => { - if(postImages.length !== postImgUrls.length){ + const _handleSetSelectedImage = (imageLink: string, postImgUrls: string[]) => { + if (postImages.length !== postImgUrls.length) { setPostImages(postImgUrls); } setSelectedImage(imageLink); actionImage.current.show(); - } + }; const _handleOnPostPress = (permlink, author) => { - if(handleOnPostPress){ + if (handleOnPostPress) { handleOnUserPress(permlink, author); return; } @@ -179,7 +175,7 @@ const CommentBody = ({ }; const _handleOnUserPress = (username) => { - if(handleOnUserPress){ + if (handleOnUserPress) { handleOnUserPress(username); return; } @@ -279,17 +275,16 @@ const CommentBody = ({ const _handleVideoPress = (embedUrl) => { if (embedUrl && youtubePlayerRef.current) { setVideoUrl(embedUrl); - setVideoStartTime(0) + setVideoStartTime(0); youtubePlayerRef.current.setModalVisible(true); } }; - return ( ({url}))} + imageUrls={postImages.map((url) => ({ url }))} enableSwipeDown onCancel={() => setIsImageModalOpen(false)} onClick={() => setIsImageModalOpen(false)} @@ -339,7 +334,6 @@ const CommentBody = ({ /> - ) : ( - @@ -371,4 +365,3 @@ const CommentBody = ({ }; export default CommentBody; - diff --git a/src/components/postHtmlRenderer/postHtmlRenderer.tsx b/src/components/postHtmlRenderer/postHtmlRenderer.tsx index d70ee2388..25caa0b02 100644 --- a/src/components/postHtmlRenderer/postHtmlRenderer.tsx +++ b/src/components/postHtmlRenderer/postHtmlRenderer.tsx @@ -1,21 +1,21 @@ import React, { memo, useMemo, useRef } from 'react'; import RenderHTML, { CustomRendererProps, Element, TNode } from 'react-native-render-html'; import { useHtmlIframeProps, iframeModel } from '@native-html/iframe-plugin'; +import WebView from 'react-native-webview'; +import { ScrollView } from 'react-native-gesture-handler'; +import { prependChild, removeElement } from 'htmlparser2/node_modules/domutils'; import styles from './postHtmlRendererStyles'; import { LinkData, parseLinkData } from './linkDataParser'; import VideoThumb from './videoThumb'; import { AutoHeightImage } from '../autoHeightImage/autoHeightImage'; -import WebView from 'react-native-webview'; import { VideoPlayer } from '..'; -import { ScrollView } from 'react-native-gesture-handler'; -import { prependChild, removeElement } from 'htmlparser2/node_modules/domutils'; interface PostHtmlRendererProps { contentWidth: number; body: string; isComment?: boolean; onLoaded?: () => void; - setSelectedImage: (imgUrl: string, postImageUrls:string[]) => void; + setSelectedImage: (imgUrl: string, postImageUrls: string[]) => void; setSelectedLink: (url: string) => void; handleOnPostPress: (permlink: string, authro: string) => void; handleOnUserPress: (username: string) => void; @@ -38,7 +38,6 @@ export const PostHtmlRenderer = memo( handleVideoPress, handleYoutubePress, }: PostHtmlRendererProps) => { - const postImgUrlsRef = useRef([]); //new renderer functions @@ -146,8 +145,8 @@ export const PostHtmlRenderer = memo( if (element.tagName === 'img' && element.attribs.src) { const imgUrl = element.attribs.src; console.log('img element detected', imgUrl); - if(!postImgUrlsRef.current.includes(imgUrl)){ - postImgUrlsRef.current.push(imgUrl) + if (!postImgUrlsRef.current.includes(imgUrl)) { + postImgUrlsRef.current.push(imgUrl); } } @@ -291,7 +290,6 @@ export const PostHtmlRenderer = memo( ); }; - // iframe renderer for rendering iframes in body const _iframeRenderer = function IframeRenderer(props) { const iframeProps = useHtmlIframeProps(props); diff --git a/src/components/postHtmlRenderer/postHtmlRendererStyles.ts b/src/components/postHtmlRenderer/postHtmlRendererStyles.ts index 0a6385c89..f83e8897e 100644 --- a/src/components/postHtmlRenderer/postHtmlRendererStyles.ts +++ b/src/components/postHtmlRenderer/postHtmlRendererStyles.ts @@ -1,5 +1,5 @@ -import { ImageStyle, Platform } from 'react-native'; -import { ViewStyle, TextStyle } from 'react-native'; +import { ImageStyle, Platform, ViewStyle, TextStyle } from 'react-native'; + import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ @@ -13,82 +13,82 @@ export default EStyleSheet.create({ color: '$primaryBlack', } as TextStyle, div: { - width:'100%', - }, - p:{ - marginTop:6, - marginBottom:6, - flexDirection:'row', - alignItems:'center', - flexWrap:'wrap' - } as TextStyle, - h6:{ - fontSize:14, - } as TextStyle, - pLi:{ - marginTop:0, - marginBottom:0 - } as TextStyle, - a:{ - color: '$primaryBlue' - } as TextStyle, - img:{ width: '100%', - alignSelf:'center', - marginTop:4, - marginBottom:4, - backgroundColor:'red' + }, + p: { + marginTop: 6, + marginBottom: 6, + flexDirection: 'row', + alignItems: 'center', + flexWrap: 'wrap', + } as TextStyle, + h6: { + fontSize: 14, + } as TextStyle, + pLi: { + marginTop: 0, + marginBottom: 0, + } as TextStyle, + a: { + color: '$primaryBlue', + } as TextStyle, + img: { + width: '100%', + alignSelf: 'center', + marginTop: 4, + marginBottom: 4, + backgroundColor: 'red', } as ImageStyle, - th:{ + th: { flex: 1, justifyContent: 'center', - alignItems:'center', + alignItems: 'center', fontWeight: 'bold', color: '$primaryBlack', - backgroundColor:'$darkIconColor', + backgroundColor: '$darkIconColor', fontSize: 14, padding: 10, } as TextStyle, - tr:{ - flexDirection:'row', + tr: { + flexDirection: 'row', } as ViewStyle, - td:{ - flex:1, + td: { + flex: 1, borderWidth: 0.5, - padding:10, + padding: 10, borderColor: '$tableBorderColor', backgroundColor: '$tableTrColor', - alignItems:'center', - justifyContent:'center', + alignItems: 'center', + justifyContent: 'center', } as ViewStyle, - table:{ - width: '100%', + table: { + width: '100%', } as ViewStyle, - li:{ - marginBottom:12 + li: { + marginBottom: 12, } as ViewStyle, blockquote: { borderLeftWidth: 5, - borderStyle:'solid', - marginLeft:5, - paddingLeft:5, + borderStyle: 'solid', + marginLeft: 5, + paddingLeft: 5, borderColor: '$darkIconColor', } as ViewStyle, - code:{ - backgroundColor:'$darkIconColor', - fontFamily:'$editorFont', + code: { + backgroundColor: '$darkIconColor', + fontFamily: '$editorFont', } as TextStyle, textCenter: { textAlign: 'center', alignItems: 'center', justifyContent: 'center', } as TextStyle, - phishy:{ - color:'$primaryRed', + phishy: { + color: '$primaryRed', } as TextStyle, - textJustify:{ - textAlign: Platform.select({ios:'justify', android:'auto'}), //justify with selectable on android causes ends of text getting clipped, - letterSpacing:0 + textJustify: { + textAlign: Platform.select({ ios: 'justify', android: 'auto' }), //justify with selectable on android causes ends of text getting clipped, + letterSpacing: 0, } as TextStyle, revealButton: { backgroundColor: '$iconColor', @@ -103,20 +103,18 @@ export default EStyleSheet.create({ color: '$white', fontSize: 14, }, - videoThumb:{ - width:'100%', - alignItems:'center', - justifyContent:'center', - backgroundColor:'$darkIconColor' + videoThumb: { + width: '100%', + alignItems: 'center', + justifyContent: 'center', + backgroundColor: '$darkIconColor', }, - playButton:{ - alignItems:'center', - justifyContent:'center', + playButton: { + alignItems: 'center', + justifyContent: 'center', width: 60, height: 60, borderRadius: 30, - backgroundColor:'$primaryBlack' - } as ViewStyle + backgroundColor: '$primaryBlack', + } as ViewStyle, }); - - diff --git a/src/components/postView/view/postDisplayView.tsx b/src/components/postView/view/postDisplayView.tsx index 79574a497..1918b61ed 100644 --- a/src/components/postView/view/postDisplayView.tsx +++ b/src/components/postView/view/postDisplayView.tsx @@ -70,8 +70,8 @@ const PostDisplayView = ({ if (isLoggedIn && get(currentAccount, 'name') && !isNewPost) { //track user activity for view post userActivityMutation.mutate({ - pointsTy:PointActivityIds.VIEW_POST - }) + pointsTy: PointActivityIds.VIEW_POST, + }); } }, []); diff --git a/src/components/postsList/container/postsListContainer.tsx b/src/components/postsList/container/postsListContainer.tsx index 371bff615..402040910 100644 --- a/src/components/postsList/container/postsListContainer.tsx +++ b/src/components/postsList/container/postsListContainer.tsx @@ -1,28 +1,29 @@ -import React, {forwardRef, memo, useRef, useImperativeHandle, useState, useEffect} from 'react' -import PostCard from '../../postCard'; +import React, { forwardRef, memo, useRef, useImperativeHandle, useState, useEffect } from 'react'; import { get } from 'lodash'; import { FlatListProps, FlatList, RefreshControl, ActivityIndicator, View } from 'react-native'; import { useSelector } from 'react-redux'; +import PostCard from '../../postCard'; import { ThemeContainer } from '../../../containers'; import styles from '../view/postsListStyles'; export interface PostsListRef { - scrollToTop:()=>void + scrollToTop: () => void; } interface postsListContainerProps extends FlatListProps { - promotedPosts:Array; - isFeedScreen:boolean; - onLoadPosts?:(shouldReset:boolean)=>void; - isLoading:boolean; - isRefreshing:boolean; - pageType:'main'|'profile'|'ownProfile'|'community'; - showQuickReplyModal:(post:any)=>void; + promotedPosts: Array; + isFeedScreen: boolean; + onLoadPosts?: (shouldReset: boolean) => void; + isLoading: boolean; + isRefreshing: boolean; + pageType: 'main' | 'profile' | 'ownProfile' | 'community'; + showQuickReplyModal: (post: any) => void; } let _onEndReachedCalledDuringMomentum = true; -const postsListContainer = ({ +const postsListContainer = ( + { promotedPosts, isFeedScreen, onLoadPosts, @@ -31,65 +32,61 @@ const postsListContainer = ({ pageType, showQuickReplyModal, ...props -}:postsListContainerProps, ref) => { - + }: postsListContainerProps, + ref, +) => { + const flatListRef = useRef(null); - const [imageHeights, setImageHeights] = useState(new Map()); + const [imageHeights, setImageHeights] = useState(new Map()); - const isHideImages = useSelector((state) => state.application.hidePostsThumbnails); - const posts = useSelector((state) => { - return isFeedScreen - ? state.posts.feedPosts - : state.posts.otherPosts - }); - const mutes = useSelector((state) => state.account.currentAccount.mutes); - - const scrollPosition = useSelector((state) => { - return isFeedScreen - ? state.posts.feedScrollPosition - : state.posts.otherScrollPosition + const isHideImages = useSelector((state) => state.application.hidePostsThumbnails); + const posts = useSelector((state) => { + return isFeedScreen ? state.posts.feedPosts : state.posts.otherPosts; + }); + const mutes = useSelector((state) => state.account.currentAccount.mutes); + + const scrollPosition = useSelector((state) => { + return isFeedScreen ? state.posts.feedScrollPosition : state.posts.otherScrollPosition; }); - useImperativeHandle(ref, () => ({ - scrollToTop() { - flatListRef.current?.scrollToOffset({ x: 0, y: 0, animated: true }); - }, - })); + useImperativeHandle(ref, () => ({ + scrollToTop() { + flatListRef.current?.scrollToOffset({ x: 0, y: 0, animated: true }); + }, + })); - useEffect(() => { - console.log("Scroll Position: ", scrollPosition) - if(posts && posts.length == 0){ - flatListRef.current?.scrollToOffset({ - offset: 0, - animated: false - }); - } - - }, [posts]) - - useEffect(() => { - console.log("Scroll Position: ", scrollPosition) + useEffect(() => { + console.log('Scroll Position: ', scrollPosition); + if (posts && posts.length == 0) { flatListRef.current?.scrollToOffset({ - offset: (posts && posts.length == 0) ? 0 : scrollPosition, - animated: false + offset: 0, + animated: false, }); - - }, [scrollPosition]) - - const _setImageHeightInMap = (mapKey:string, height:number) => { - if(mapKey && height){ - setImageHeights(imageHeights.set(mapKey, height)); - } } + }, [posts]); + useEffect(() => { + console.log('Scroll Position: ', scrollPosition); + flatListRef.current?.scrollToOffset({ + offset: posts && posts.length == 0 ? 0 : scrollPosition, + animated: false, + }); + + }, [scrollPosition]); + + const _setImageHeightInMap = (mapKey: string, height: number) => { + if (mapKey && height) { + setImageHeights(imageHeights.set(mapKey, height)); + } + }; const _renderFooter = () => { if (isLoading && !isRefreshing) { return ( - + ); } @@ -104,96 +101,103 @@ const postsListContainer = ({ } }; + const _renderItem = ({ item, index }: { item: any; index: number }) => { + const e = [] as any; - const _renderItem = ({ item, index }:{item:any, index:number}) => { - const e = [] as any; - - if (index % 3 === 0) { - const ix = index / 3 - 1; - if (promotedPosts[ix] !== undefined) { - const p = promotedPosts[ix]; - let isMuted = mutes && mutes.indexOf(p.author) > -1; + if (index % 3 === 0) { + const ix = index / 3 - 1; + if (promotedPosts[ix] !== undefined) { + const p = promotedPosts[ix]; + let isMuted = mutes && mutes.indexOf(p.author) > -1; - if (!isMuted && get(p, 'author', null) && posts && posts.filter((x) => x.permlink === p.permlink).length <= 0) { - - //get image height from cache if available - const localId = p.author + p.permlink; - const imgHeight = imageHeights.get(localId); + if ( + !isMuted && + get(p, 'author', null) && + posts && + posts.filter((x) => x.permlink === p.permlink).length <= 0 - e.push( - - ); - } - } - } - - let isMuted = mutes && mutes.indexOf(item.author) > -1; - if (!isMuted && get(item, 'author', null)) { //get image height from cache if available - const localId = item.author + item.permlink; - const imgHeight = imageHeights.get(localId) + const localId = p.author + p.permlink; + const imgHeight = imageHeights.get(localId); e.push( , ); } - return e; - }; - - return ( - - {({ isDarkTheme }) => ( - `${content.author}/${content.permlink}-${index}`} - removeClippedSubviews - onEndReachedThreshold={1} - maxToRenderPerBatch={3} - initialNumToRender={3} - windowSize={5} - extraData={imageHeights} - onEndReached={_onEndReached} - onMomentumScrollBegin={() => { - _onEndReachedCalledDuringMomentum = false; + } + } + + let isMuted = mutes && mutes.indexOf(item.author) > -1; + if (!isMuted && get(item, 'author', null)) { + //get image height from cache if available + const localId = item.author + item.permlink; + const imgHeight = imageHeights.get(localId); + + e.push( + , + ); + } + return e; + }; + + return ( + + {({ isDarkTheme }) => ( + `${content.author}/${content.permlink}-${index}`} + removeClippedSubviews + onEndReachedThreshold={1} + maxToRenderPerBatch={3} + initialNumToRender={3} + windowSize={5} + extraData={imageHeights} + onEndReached={_onEndReached} + onMomentumScrollBegin={() => { + _onEndReachedCalledDuringMomentum = false; + }} + ListFooterComponent={_renderFooter} + refreshControl={ + { + if (onLoadPosts) { + onLoadPosts(true); + } }} - ListFooterComponent={_renderFooter} - refreshControl={ - {if(onLoadPosts){onLoadPosts(true)}}} - progressBackgroundColor="#357CE6" - tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'} - titleColor="#fff" - colors={['#fff']} - /> - } - {...props} - /> - )} - - ) -} + progressBackgroundColor="#357CE6" + tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'} + titleColor="#fff" + colors={['#fff']} + /> + } + {...props} + /> + )} + + ); +}; export default forwardRef(postsListContainer); diff --git a/src/components/profile/children/commentsTabContent.tsx b/src/components/profile/children/commentsTabContent.tsx index 3ca52e153..d719e7432 100644 --- a/src/components/profile/children/commentsTabContent.tsx +++ b/src/components/profile/children/commentsTabContent.tsx @@ -1,133 +1,130 @@ -import React, {useEffect, useState} from 'react'; +import React, { useEffect, useState } from 'react'; import { useIntl } from 'react-intl'; -import {ActivityIndicator, RefreshControl, View } from 'react-native'; +import { ActivityIndicator, RefreshControl, View } from 'react-native'; +import { unionBy } from 'lodash'; import { Comments, NoPost } from '../..'; import { useAppSelector } from '../../../hooks'; import { getAccountPosts } from '../../../providers/hive/dhive'; import styles from '../profileStyles'; -import {unionBy } from 'lodash'; interface CommentsTabContentProps { - username:string, - type:'comments'|'replies', - isOwnProfile:boolean, - selectedUser:any, - onScroll:()=>void, + username: string; + type: 'comments' | 'replies'; + isOwnProfile: boolean; + selectedUser: any; + onScroll: () => void; } -const CommentsTabContent = ({isOwnProfile, username, type, onScroll, selectedUser }: CommentsTabContentProps) => { +const CommentsTabContent = ({ + isOwnProfile, + username, + type, + onScroll, + selectedUser, +}: CommentsTabContentProps) => { + const intl = useIntl(); - const intl = useIntl(); + const isHideImage = useAppSelector((state) => state.application.hidePostsThumbnails); - const isHideImage = useAppSelector(state => state.application.hidePostsThumbnails); + const [data, setData] = useState([]); + const [lastAuthor, setLastAuthor] = useState(''); + const [lastPermlink, setLastPermlink] = useState(''); + const [loading, setLoading] = useState(false); + const [refreshing, setRefreshing] = useState(false); + const [noMore, setNoMore] = useState(false); - const [data, setData] = useState([]); - const [lastAuthor, setLastAuthor] = useState(''); - const [lastPermlink, setLastPermlink] = useState(''); - const [loading, setLoading] = useState(false); - const [refreshing, setRefreshing] = useState(false); - const [noMore, setNoMore] = useState(false); + useEffect(() => { + if (selectedUser) { + _fetchData(); + } + }, [selectedUser]); - - useEffect(() => { - if(selectedUser){ - _fetchData(); - } - }, [selectedUser]) - - - const _fetchData = async ({refresh}:{refresh?:boolean} = {}) => { - if(loading || (!refresh && noMore)){ - return; - } - - setLoading(true); - if(refresh){ - setRefreshing(true); - } - - const query:any = { - account:username, - start_author: refresh ? '' : lastAuthor, - start_permlink: refresh ? '' : lastPermlink, - limit:10, - observer:'', - sort:type - }; - - const result = await getAccountPosts(query) - let _comments:any[] = refresh ? result : unionBy(data, result, 'permlink'); - - if(Array.isArray(_comments)){ - setData(_comments); - if(_comments.length > 0){ - setLastAuthor(_comments[_comments.lastIndex].author) - setLastPermlink(_comments[_comments.lastIndex].permlink) - } - if(result.length == 0){ - setNoMore(true); - } - }else{ - setData([]); - setNoMore(true); - } - - setLoading(false); - setRefreshing(false); - + const _fetchData = async ({ refresh }: { refresh?: boolean } = {}) => { + if (loading || (!refresh && noMore)) { + return; } - const _renderListEmpty = () => { - if(loading){ - return null - } - return ( - - ) + setLoading(true); + if (refresh) { + setRefreshing(true); } - const _renderListFooter = () => { - return ( - - {loading && ( - - )} - - ) + const query: any = { + account: username, + start_author: refresh ? '' : lastAuthor, + start_permlink: refresh ? '' : lastPermlink, + limit: 10, + observer: '', + sort: type, + }; + + const result = await getAccountPosts(query); + let _comments: any[] = refresh ? result : unionBy(data, result, 'permlink'); + + if (Array.isArray(_comments)) { + setData(_comments); + if (_comments.length > 0) { + setLastAuthor(_comments[_comments.lastIndex].author); + setLastPermlink(_comments[_comments.lastIndex].permlink); + } + if (result.length == 0) { + setNoMore(true); + } + } else { + setData([]); + setNoMore(true); } + setLoading(false); + setRefreshing(false); + }; + const _renderListEmpty = () => { + if (loading) { + return null; + } return ( - - {}} - isOwnProfile={isOwnProfile} - isHideImage={isHideImage} - flatListProps={{ - onEndReached:_fetchData, - onScroll:onScroll, - ListEmptyComponent:_renderListEmpty, - ListFooterComponent:_renderListFooter, - onEndReachedThreshold:1, - refreshControl:( - _fetchData({refresh:true})} - /> - ) - }} - /> - + ); + }; + + const _renderListFooter = () => { + return ( + {loading && } + ); + }; + + return ( + + {}} + isOwnProfile={isOwnProfile} + isHideImage={isHideImage} + flatListProps={{ + onEndReached: _fetchData, + onScroll: onScroll, + ListEmptyComponent: _renderListEmpty, + ListFooterComponent: _renderListFooter, + onEndReachedThreshold: 1, + refreshControl: ( + _fetchData({ refresh: true })} + /> + ), + }} + /> + + ); }; export default CommentsTabContent; diff --git a/src/components/profileEditForm/profileEditFormView.tsx b/src/components/profileEditForm/profileEditFormView.tsx index 1c814b8f3..74f84a554 100644 --- a/src/components/profileEditForm/profileEditFormView.tsx +++ b/src/components/profileEditForm/profileEditFormView.tsx @@ -6,6 +6,8 @@ import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view import { injectIntl } from 'react-intl'; // Images +import FastImage from 'react-native-fast-image'; +import EStyleSheet from 'react-native-extended-stylesheet'; import LIGHT_COVER_IMAGE from '../../assets/default_cover_image.png'; import DARK_COVER_IMAGE from '../../assets/dark_cover_image.png'; @@ -18,22 +20,19 @@ import { getResizedImage } from '../../utils/image'; // Styles import styles from './profileEditFormStyles'; -import FastImage from 'react-native-fast-image'; -import EStyleSheet from 'react-native-extended-stylesheet'; import { MainButton } from '../mainButton'; - interface ProfileEditFormProps { - coverUrl:string; - formData:any; - handleOnItemChange:()=>void; - handleOnSubmit:()=>void; - intl:any, - isDarkTheme:boolean, - isLoading:boolean, - isUploading:boolean, - showImageUploadActions:boolean, - saveEnabled:boolean, + coverUrl: string; + formData: any; + handleOnItemChange: () => void; + handleOnSubmit: () => void; + intl: any; + isDarkTheme: boolean; + isLoading: boolean; + isUploading: boolean; + showImageUploadActions: boolean; + saveEnabled: boolean; } const ProfileEditFormView = ({ @@ -48,37 +47,31 @@ const ProfileEditFormView = ({ showImageUploadActions, saveEnabled, ...props -}:ProfileEditFormProps) => ( - +}: ProfileEditFormProps) => ( - - - - { - isUploading && ( - - ) + + {isUploading && ( + + )} ))} - + {saveEnabled && ( )} - - ); diff --git a/src/components/qrModal/qrModalView.tsx b/src/components/qrModal/qrModalView.tsx index c3ce4d6fd..e45b5b30b 100644 --- a/src/components/qrModal/qrModalView.tsx +++ b/src/components/qrModal/qrModalView.tsx @@ -2,14 +2,14 @@ import React, { useEffect, useRef, useState } from 'react'; import { ActivityIndicator, Alert, PermissionsAndroid, Platform, Text, View } from 'react-native'; import ActionSheet from 'react-native-actions-sheet'; 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 styles from './qrModalStyles'; import { useAppDispatch, useAppSelector } from '../../hooks'; import { toggleQRModal } from '../../redux/actions/uiAction'; -import QRCodeScanner from 'react-native-qrcode-scanner'; import { deepLinkParser } from '../../utils/deepLinkParser'; -import { useIntl } from 'react-intl'; import { navigate } from '../../navigation/service'; -import { check, request, PERMISSIONS, RESULTS, openSettings } from 'react-native-permissions'; import getWindowDimensions from '../../utils/getWindowDimensions'; export interface QRModalProps {} @@ -155,7 +155,7 @@ export const QRModal = ({}: QRModalProps) => { /> {isProcessing && ( - + )} diff --git a/src/components/quickReplyModal/quickReplyModalContent.tsx b/src/components/quickReplyModal/quickReplyModalContent.tsx index 1e80931f8..0824dedfd 100644 --- a/src/components/quickReplyModal/quickReplyModalContent.tsx +++ b/src/components/quickReplyModal/quickReplyModalContent.tsx @@ -1,10 +1,19 @@ -import React, { useEffect, useState, useCallback, useRef } from 'react'; +import React, { + useEffect, + useState, + useCallback, + useRef, + useImperativeHandle, + forwardRef, +} from 'react'; import EStyleSheet from 'react-native-extended-stylesheet'; -import styles from './quickReplyModalStyles'; import { View, Text, Alert, TouchableOpacity, Keyboard, Platform } from 'react-native'; import { useIntl } from 'react-intl'; -import { IconButton, MainButton, TextButton, TextInput, UserAvatar } from '..'; import { useSelector, useDispatch } from 'react-redux'; +import { get } from 'lodash'; +import { postBodySummary } from '@ecency/render-helper'; +import styles from './quickReplyModalStyles'; +import { IconButton, MainButton, TextButton, TextInput, UserAvatar } from '..'; import { delay, generateReplyPermlink, generateRndStr } from '../../utils/editor'; import { postComment } from '../../providers/hive/dhive'; import { toastNotification } from '../../redux/actions/uiAction'; @@ -14,13 +23,10 @@ import { updateDraftCache, } from '../../redux/actions/cacheActions'; import { default as ROUTES } from '../../constants/routeNames'; -import { get } from 'lodash'; import { navigate } from '../../navigation/service'; -import { postBodySummary } from '@ecency/render-helper'; import { Draft } from '../../redux/reducers/cacheReducer'; import { RootState } from '../../redux/store/store'; -import { useImperativeHandle } from 'react'; -import { forwardRef } from 'react'; + import { PointActivityIds } from '../../providers/ecency/ecency.types'; import { useUserActivityMutation } from '../../providers/queries/pointQueries'; @@ -30,299 +36,280 @@ export interface QuickReplyModalContentProps { onClose: () => void; } -export const QuickReplyModalContent = forwardRef(({ - selectedPost, - onClose, -}: QuickReplyModalContentProps, ref) => { - const intl = useIntl(); - const dispatch = useDispatch(); - const userActivityMutation = useUserActivityMutation(); +export const QuickReplyModalContent = forwardRef( + ({ selectedPost, onClose }: QuickReplyModalContentProps, ref) => { + const intl = useIntl(); + const dispatch = useDispatch(); + const userActivityMutation = useUserActivityMutation(); - const inputRef = useRef(null); + const inputRef = useRef(null); - const currentAccount = useSelector((state: RootState) => state.account.currentAccount); - const pinCode = useSelector((state: RootState) => state.application.pin); - const drafts = useSelector((state: RootState) => state.cache.drafts); + const currentAccount = useSelector((state: RootState) => state.account.currentAccount); + const pinCode = useSelector((state: RootState) => state.application.pin); + const drafts = useSelector((state: RootState) => state.cache.drafts); - const [commentValue, setCommentValue] = useState(''); - const [isSending, setIsSending] = useState(false); + const [commentValue, setCommentValue] = useState(''); + const [isSending, setIsSending] = useState(false); + const headerText = + selectedPost && + (selectedPost.summary || postBodySummary(selectedPost, 150, Platform.OS as any)); + let parentAuthor = selectedPost ? selectedPost.author : ''; + let parentPermlink = selectedPost ? selectedPost.permlink : ''; + let draftId = `${currentAccount.name}/${parentAuthor}/${parentPermlink}`; //different draftId for each user acount - const headerText = - selectedPost && (selectedPost.summary || postBodySummary(selectedPost, 150, Platform.OS as any)); - let parentAuthor = selectedPost ? selectedPost.author : ''; - let parentPermlink = selectedPost ? selectedPost.permlink : ''; - let draftId = `${currentAccount.name}/${parentAuthor}/${parentPermlink}`; //different draftId for each user acount + useImperativeHandle(ref, () => ({ + handleSheetClose() { + _addQuickCommentIntoCache(); + }, + })); + // load quick comment value from cache + useEffect(() => { + let _value = ''; + if (drafts.has(draftId) && currentAccount.name === drafts.get(draftId).author) { + const quickComment: Draft = drafts.get(draftId); + _value = quickComment.body; + } - useImperativeHandle(ref, () => ({ - handleSheetClose() { - _addQuickCommentIntoCache(); - }, - })); + if (inputRef.current) { + inputRef.current.setNativeProps({ + text: _value, + }); + setCommentValue(_value); + } + }, [selectedPost]); + // add quick comment value into cache + const _addQuickCommentIntoCache = (value = commentValue) => { + const quickCommentDraftData: Draft = { + author: currentAccount.name, + body: value, + }; - // load quick comment value from cache - useEffect(() => { - let _value = '' - if (drafts.has(draftId) && currentAccount.name === drafts.get(draftId).author) { - const quickComment: Draft = drafts.get(draftId); - _value = quickComment.body; - } - - if (inputRef.current) { - inputRef.current.setNativeProps({ - text: _value - }) - setCommentValue(_value) - } - - }, [selectedPost]); - - - - // add quick comment value into cache - const _addQuickCommentIntoCache = (value = commentValue) => { - - const quickCommentDraftData: Draft = { - author: currentAccount.name, - body: value + //add quick comment cache entry + dispatch(updateDraftCache(draftId, quickCommentDraftData)); }; - //add quick comment cache entry - dispatch(updateDraftCache(draftId, quickCommentDraftData)); - }; + // handle close press + const _handleClosePress = () => { + onClose(); + }; - - // handle close press - const _handleClosePress = () => { - onClose() - }; - - - // navigate to post on summary press - const _handleOnSummaryPress = () => { - Keyboard.dismiss(); - onClose(); - navigate({ - routeName: ROUTES.SCREENS.POST, - params: { - content: selectedPost, - }, - key: get(selectedPost, 'permlink'), - }); - }; - - - // handle submit reply - const _submitReply = async () => { - - if (!commentValue) { - return; - } - if (isSending) { - return; - } - - if (currentAccount) { - setIsSending(true); - - const permlink = generateReplyPermlink(selectedPost.author); - - const parentAuthor = selectedPost.author; - const parentPermlink = selectedPost.permlink; - const parentTags = selectedPost.json_metadata.tags; - console.log( - currentAccount, - pinCode, - parentAuthor, - parentPermlink, - permlink, - commentValue, - parentTags, - ); - - const status = await postComment( - currentAccount, - pinCode, - parentAuthor, - parentPermlink, - permlink, - commentValue, - parentTags, - ) - .then((response) => { - userActivityMutation.mutate({ - pointsTy:PointActivityIds.COMMENT, - transactionId:response.id - }) - setIsSending(false); - setCommentValue(''); - - if(inputRef.current){ - inputRef.current.setNativeProps({ - text: '' - }) - } - - dispatch( - toastNotification( - intl.formatMessage({ - id: 'alert.success', - }), - ), - ); - - //add comment cache entry - dispatch( - updateCommentCache( - `${parentAuthor}/${parentPermlink}`, - { - author: currentAccount.name, - permlink, - parent_author: parentAuthor, - parent_permlink: parentPermlink, - markdownBody: commentValue, - }, - { - parentTags: parentTags || ['ecency'], - }, - ), - ); - - // delete quick comment draft cache if it exist - if (drafts.has(draftId)) { - dispatch(deleteDraftCacheEntry(draftId)); - } - - //close should alwasy be called at method end - onClose(); - }) - .catch((error) => { - console.log(error); - Alert.alert( - intl.formatMessage({ - id: 'alert.fail', - }), - error.message || JSON.stringify(error), - ); - - - setIsSending(false); - _addQuickCommentIntoCache(); //add comment value into cache if there is error while posting comment - - }); - console.log('status : ', status); - } - }; - - const _handleExpandBtn = async () => { - if (selectedPost) { + // navigate to post on summary press + const _handleOnSummaryPress = () => { Keyboard.dismiss(); onClose(); - await delay(50); navigate({ - routeName: ROUTES.SCREENS.EDITOR, - key: 'editor_replay', + routeName: ROUTES.SCREENS.POST, params: { - isReply: true, - post: selectedPost, + content: selectedPost, }, + key: get(selectedPost, 'permlink'), }); - } - }; + }; + // handle submit reply + const _submitReply = async () => { + if (!commentValue) { + return; + } + if (isSending) { + return; + } - //REMOVED FOR TESTING, CAN BE PUT BACK IF APP STILL CRASHES - // const _deboucedCacheUpdate = useCallback(debounce(_addQuickCommentIntoCache, 500), []) + if (currentAccount) { + setIsSending(true); + + const permlink = generateReplyPermlink(selectedPost.author); + + const parentAuthor = selectedPost.author; + const parentPermlink = selectedPost.permlink; + const parentTags = selectedPost.json_metadata.tags; + console.log( + currentAccount, + pinCode, + parentAuthor, + parentPermlink, + permlink, + commentValue, + parentTags, + ); + + const status = await postComment( + currentAccount, + pinCode, + parentAuthor, + parentPermlink, + permlink, + commentValue, + parentTags, + ) + .then((response) => { + userActivityMutation.mutate({ + pointsTy: PointActivityIds.COMMENT, + transactionId: response.id, + }); + setIsSending(false); + setCommentValue(''); + + if (inputRef.current) { + inputRef.current.setNativeProps({ + text: '', + }); + } + + dispatch( + toastNotification( + intl.formatMessage({ + id: 'alert.success', + }), + ), + ); + + //add comment cache entry + dispatch( + updateCommentCache( + `${parentAuthor}/${parentPermlink}`, + { + author: currentAccount.name, + permlink, + parent_author: parentAuthor, + parent_permlink: parentPermlink, + markdownBody: commentValue, + }, + { + parentTags: parentTags || ['ecency'], + }, + ), + ); + + // delete quick comment draft cache if it exist + if (drafts.has(draftId)) { + dispatch(deleteDraftCacheEntry(draftId)); + } + + //close should alwasy be called at method end + onClose(); + }) + .catch((error) => { + console.log(error); + Alert.alert( + intl.formatMessage({ + id: 'alert.fail', + }), + error.message || JSON.stringify(error), + ); + + setIsSending(false); + _addQuickCommentIntoCache(); //add comment value into cache if there is error while posting comment + }); + console.log('status : ', status); + } + }; + + const _handleExpandBtn = async () => { + if (selectedPost) { + Keyboard.dismiss(); + onClose(); + await delay(50); + navigate({ + routeName: ROUTES.SCREENS.EDITOR, + key: 'editor_replay', + params: { + isReply: true, + post: selectedPost, + }, + }); + } + }; - const _onChangeText = (value) => { - setCommentValue(value); //REMOVED FOR TESTING, CAN BE PUT BACK IF APP STILL CRASHES - // _deboucedCacheUpdate(value) - } + // const _deboucedCacheUpdate = useCallback(debounce(_addQuickCommentIntoCache, 500), []) + const _onChangeText = (value) => { + setCommentValue(value); + //REMOVED FOR TESTING, CAN BE PUT BACK IF APP STILL CRASHES + // _deboucedCacheUpdate(value) + }; + //VIEW_RENDERERS - //VIEW_RENDERERS + const _renderSummary = () => ( + _handleOnSummaryPress()}> + + {headerText} + + + ); - - const _renderSummary = () => ( - _handleOnSummaryPress()}> - - {headerText} - - - ); - - const _renderAvatar = () => ( - - - - {`@${currentAccount.username}`} + const _renderAvatar = () => ( + + + + {`@${currentAccount.username}`} + - - ); + ); - const _renderExpandBtn = () => ( - - - - ); - const _renderReplyBtn = () => ( - - - _submitReply()} - text={intl.formatMessage({ - id: 'quick_reply.reply', - })} - isLoading={isSending} - /> - - ); - - - - const _renderContent = ( - - {_renderSummary()} - {_renderAvatar()} - - ( + + - - {_renderExpandBtn()} - {_renderReplyBtn()} + ); + const _renderReplyBtn = () => ( + + + _submitReply()} + text={intl.formatMessage({ + id: 'quick_reply.reply', + })} + isLoading={isSending} + /> - - ) + ); - return _renderContent -}); + const _renderContent = ( + + {_renderSummary()} + {_renderAvatar()} + + + + + {_renderExpandBtn()} + {_renderReplyBtn()} + + + ); + + return _renderContent; + }, +); diff --git a/src/components/quickReplyModal/quickReplyModalStyles.ts b/src/components/quickReplyModal/quickReplyModalStyles.ts index 3ff62044a..f76c0ec9e 100644 --- a/src/components/quickReplyModal/quickReplyModalStyles.ts +++ b/src/components/quickReplyModal/quickReplyModalStyles.ts @@ -3,18 +3,18 @@ import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ sheetContent: { backgroundColor: '$primaryBackgroundColor', - marginTop:132, + marginTop: 132, }, container: { flex: 1, - justifyContent:"flex-end", + justifyContent: 'flex-end', backgroundColor: 'rgba(0, 0, 0, 0.2)', }, modalContainer: { - margin:16, - borderRadius:16, + margin: 16, + borderRadius: 16, backgroundColor: '$primaryBackgroundColor', paddingTop: 16, paddingBottom: 16, @@ -44,7 +44,7 @@ export default EStyleSheet.create({ }, textInput: { color: '$primaryBlack', - paddingHorizontal:16, + paddingHorizontal: 16, fontSize: 16, flexGrow: 1, fontWeight: '500', diff --git a/src/components/quickReplyModal/quickReplyModalView.tsx b/src/components/quickReplyModal/quickReplyModalView.tsx index 047fec761..c4082407b 100644 --- a/src/components/quickReplyModal/quickReplyModalView.tsx +++ b/src/components/quickReplyModal/quickReplyModalView.tsx @@ -5,34 +5,27 @@ import { useAppDispatch, useAppSelector } from '../../hooks'; import { hideReplyModal } from '../../redux/actions/uiAction'; const QuickReplyModal = () => { - const dispatch = useAppDispatch(); const replyModalVisible = useAppSelector((state) => state.ui.replyModalVisible); - const replyModalPost = useAppSelector(state => state.ui.replyModalPost) + const replyModalPost = useAppSelector((state) => state.ui.replyModalPost); const modalContentRef = useRef(null); - const _onClose = () => { - if(modalContentRef.current){ + if (modalContentRef.current) { modalContentRef.current.handleSheetClose(); } dispatch(hideReplyModal()); - } - + }; return ( - + - ); }; diff --git a/src/components/simpleChart/index.ts b/src/components/simpleChart/index.ts index b36f7beda..cf70a288d 100644 --- a/src/components/simpleChart/index.ts +++ b/src/components/simpleChart/index.ts @@ -1 +1 @@ -export * from './simpleChart'; \ No newline at end of file +export * from './simpleChart'; diff --git a/src/components/simpleChart/simpleChart.tsx b/src/components/simpleChart/simpleChart.tsx index b849b2d18..fcdc1deb4 100644 --- a/src/components/simpleChart/simpleChart.tsx +++ b/src/components/simpleChart/simpleChart.tsx @@ -1,50 +1,54 @@ -import React from 'react' -import { LineChart } from 'react-native-chart-kit' +import React from 'react'; +import { LineChart } from 'react-native-chart-kit'; import EStyleSheet from 'react-native-extended-stylesheet'; interface CoinChartProps { - data:number[], - baseWidth:number, - chartHeight:number, - showLine:boolean, - showLabels?:boolean, + data: number[]; + baseWidth: number; + chartHeight: number; + showLine: boolean; + showLabels?: boolean; } -export const SimpleChart = ({data, baseWidth, chartHeight, showLine, showLabels = false}:CoinChartProps) => { - - if(!data || !data.length){ - return null; - } - - const _chartWidth = baseWidth + baseWidth/(data.length -1) - const _chartBackgroundColor = EStyleSheet.value('$primaryLightBackground'); - return ( - EStyleSheet.value('$primaryDarkText'), - color: () => showLine?EStyleSheet.value('$chartBlue'):'transparent', - }} - /> - ) -} +export const SimpleChart = ({ + data, + baseWidth, + chartHeight, + showLine, + showLabels = false, +}: CoinChartProps) => { + if (!data || !data.length) { + return null; + } + const _chartWidth = baseWidth + baseWidth / (data.length - 1); + const _chartBackgroundColor = EStyleSheet.value('$primaryLightBackground'); + return ( + EStyleSheet.value('$primaryDarkText'), + color: () => (showLine ? EStyleSheet.value('$chartBlue') : 'transparent'), + }} + /> + ); +}; diff --git a/src/components/tabbedPosts/services/tabbedPostsFetch.ts b/src/components/tabbedPosts/services/tabbedPostsFetch.ts index 9aa43c04c..061230c70 100644 --- a/src/components/tabbedPosts/services/tabbedPostsFetch.ts +++ b/src/components/tabbedPosts/services/tabbedPostsFetch.ts @@ -1,192 +1,192 @@ -import { getAccountPosts, getPost, getRankedPosts } from "../../../providers/hive/dhive"; -import { filterLatestPosts, getUpdatedPosts } from "./tabbedPostsHelpers"; -import { LoadPostsOptions } from "./tabbedPostsModels"; -import { getPromotedEntries } from "../../../providers/ecency/ecency"; +import { getAccountPosts, getPost, getRankedPosts } from '../../../providers/hive/dhive'; +import { filterLatestPosts, getUpdatedPosts } from './tabbedPostsHelpers'; +import { LoadPostsOptions } from './tabbedPostsModels'; +import { getPromotedEntries } from '../../../providers/ecency/ecency'; const POSTS_FETCH_COUNT = 20; export const loadPosts = async ({ - filterKey, - prevPosts, - tabMeta, - setTabMeta, - isLatestPostsCheck = false, - getFor, - isConnected, - isLoggedIn, - refreshing, - feedUsername, - pinnedPermlink, - pageType, - tag, - nsfw, + filterKey, + prevPosts, + tabMeta, + setTabMeta, + isLatestPostsCheck = false, + getFor, + isConnected, + isLoggedIn, + refreshing, + feedUsername, + pinnedPermlink, + pageType, + tag, + nsfw, +}: LoadPostsOptions) => { + let filter = filterKey; -}:LoadPostsOptions) => { - let filter = filterKey; - - //match filter with api if is friends - if(filter === 'friends'){ - filter = 'feed'; - } + //match filter with api if is friends + if (filter === 'friends') { + filter = 'feed'; + } - const {isLoading, startPermlink, startAuthor} = tabMeta; - - //reject update if already loading - if ( - isLoading || - !isConnected || - (!isLoggedIn && filterKey === 'feed') || - (!isLoggedIn && filterKey === 'communities') - ) { - return; - } + const { isLoading, startPermlink, startAuthor } = tabMeta; - //reject update if no connection - if (!isConnected && (refreshing || isLoading)) { - setTabMeta({ - ...tabMeta, - isLoading:false, - isRefreshing:false, - }) - return; - } + //reject update if already loading + if ( + isLoading || + !isConnected || + (!isLoggedIn && filterKey === 'feed') || + (!isLoggedIn && filterKey === 'communities') + ) { + return; + } + //reject update if no connection + if (!isConnected && (refreshing || isLoading)) { setTabMeta({ ...tabMeta, - isLoading:true, - isRefreshing:refreshing, - }) - - let options = {} as any; - const limit = isLatestPostsCheck ? 5 : POSTS_FETCH_COUNT; - let func = null; + isLoading: false, + isRefreshing: false, + }); + return; + } - if ( - filter === 'feed' || - filter === 'communities' || - filter === 'posts' || - filter === 'blog' || - getFor === 'blog' || - filter === 'reblogs' - ) { - if (filter === 'communities') { - func = getRankedPosts; - options = { - observer: feedUsername, - sort: 'created', - tag: 'my', - limit, - }; - } else { - func = getAccountPosts; - options = { - observer: feedUsername || '', - account: feedUsername, - limit, - sort: filter, - }; + setTabMeta({ + ...tabMeta, + isLoading: true, + isRefreshing: refreshing, + }); - if ((pageType === 'profile' || pageType === 'ownProfile') && (filter === 'feed' || filter === 'posts')) { - options.sort = 'posts'; - } - } - } else { + let options = {} as any; + const limit = isLatestPostsCheck ? 5 : POSTS_FETCH_COUNT; + let func = null; + + if ( + filter === 'feed' || + filter === 'communities' || + filter === 'posts' || + filter === 'blog' || + getFor === 'blog' || + filter === 'reblogs' + ) { + if (filter === 'communities') { func = getRankedPosts; options = { - tag, + observer: feedUsername, + sort: 'created', + tag: 'my', + limit, + }; + } else { + func = getAccountPosts; + options = { + observer: feedUsername || '', + account: feedUsername, limit, sort: filter, }; + + if ( + (pageType === 'profile' || pageType === 'ownProfile') && + (filter === 'feed' || filter === 'posts') + ) { + options.sort = 'posts'; + } } + } else { + func = getRankedPosts; + options = { + tag, + limit, + sort: filter, + }; + } + if (startAuthor && startPermlink && !refreshing && !isLatestPostsCheck) { + options.start_author = startAuthor; + options.start_permlink = startPermlink; + } - if (startAuthor && startPermlink && !refreshing && !isLatestPostsCheck) { - options.start_author = startAuthor; - options.start_permlink = startPermlink; - } + try { + //fetching posts + const result: any[] = await func(options, feedUsername, nsfw); - try { - //fetching posts - const result:any[] = await func(options, feedUsername, nsfw); - - if(result.length > 0){ - if(filter === 'reblogs'){ - for (let i = result.length - 1; i >= 0; i--) { - if (result[i].author === feedUsername) { - result.splice(i, 1); - } + if (result.length > 0) { + if (filter === 'reblogs') { + for (let i = result.length - 1; i >= 0; i--) { + if (result[i].author === feedUsername) { + result.splice(i, 1); } } - if((pageType === 'profile' || pageType === 'ownProfile') && pinnedPermlink){ - let pinnedIndex = -1; - result.forEach((post, index)=>{ - if(post.author === feedUsername && post.permlink === pinnedPermlink){ - pinnedIndex = index; - } - }) - result.splice(pinnedIndex, 1); - } } - - //if filter is feed convert back to reducer filter - if(filter === 'feed'){ - filter = 'friends' + if ((pageType === 'profile' || pageType === 'ownProfile') && pinnedPermlink) { + let pinnedIndex = -1; + result.forEach((post, index) => { + if (post.author === feedUsername && post.permlink === pinnedPermlink) { + pinnedIndex = index; + } + }); + result.splice(pinnedIndex, 1); } - - // cacheDispatch(updateFilterCache(filter, result, refreshing)) - setTabMeta({ - ...tabMeta, - isLoading:false, - isRefreshing:false, - }) - - const retData = { - latestPosts:null, - updatedPosts:null - } - - if(isLatestPostsCheck){ - const latestPosts = filterLatestPosts(result, prevPosts.slice(0, 5)); - retData.latestPosts = latestPosts - }else{ - const updatedPosts = getUpdatedPosts( - startAuthor && startPermlink ? prevPosts:[], - result, - refreshing, - tabMeta, - setTabMeta, - ) - - retData.updatedPosts = updatedPosts; - } - - //fetch add pinned posts if applicable - if(retData.updatedPosts && pinnedPermlink && retData.updatedPosts[0].permlink !== pinnedPermlink){ - const pinnedPost = await getPost(feedUsername, pinnedPermlink); - pinnedPost.stats = {is_pinned_blog:true, ...pinnedPost.stats}; - retData.updatedPosts = [pinnedPost, ...retData.updatedPosts]; - } - - return retData - - - } catch (err) { - setTabMeta({ - ...tabMeta, - isLoading:false, - isRefreshing:false, - }) } - }; - - - export const fetchPromotedEntries = async (username:string) => { - try { - const posts = await getPromotedEntries(username); - return Array.isArray(posts) ? posts : []; - - } catch(err){ - console.warn("Failed to get promoted posts, ", err) + //if filter is feed convert back to reducer filter + if (filter === 'feed') { + filter = 'friends'; } - } \ No newline at end of file + + // cacheDispatch(updateFilterCache(filter, result, refreshing)) + setTabMeta({ + ...tabMeta, + isLoading: false, + isRefreshing: false, + }); + + const retData = { + latestPosts: null, + updatedPosts: null, + }; + + if (isLatestPostsCheck) { + const latestPosts = filterLatestPosts(result, prevPosts.slice(0, 5)); + retData.latestPosts = latestPosts; + } else { + const updatedPosts = getUpdatedPosts( + startAuthor && startPermlink ? prevPosts : [], + result, + refreshing, + tabMeta, + setTabMeta, + ); + + retData.updatedPosts = updatedPosts; + } + + //fetch add pinned posts if applicable + if ( + retData.updatedPosts && + pinnedPermlink && + retData.updatedPosts[0].permlink !== pinnedPermlink + ) { + const pinnedPost = await getPost(feedUsername, pinnedPermlink); + pinnedPost.stats = { is_pinned_blog: true, ...pinnedPost.stats }; + retData.updatedPosts = [pinnedPost, ...retData.updatedPosts]; + } + + return retData; + } catch (err) { + setTabMeta({ + ...tabMeta, + isLoading: false, + isRefreshing: false, + }); + } +}; + +export const fetchPromotedEntries = async (username: string) => { + try { + const posts = await getPromotedEntries(username); + return Array.isArray(posts) ? posts : []; + } catch (err) { + console.warn('Failed to get promoted posts, ', err); + } +}; diff --git a/src/components/tabbedPosts/services/tabbedPostsHelpers.ts b/src/components/tabbedPosts/services/tabbedPostsHelpers.ts index da2948632..60f223e64 100644 --- a/src/components/tabbedPosts/services/tabbedPostsHelpers.ts +++ b/src/components/tabbedPosts/services/tabbedPostsHelpers.ts @@ -1,7 +1,5 @@ import unionBy from 'lodash/unionBy'; -import { TabMeta } from "./tabbedPostsModels"; - - +import { TabMeta } from './tabbedPostsModels'; //cacludate posts check refresh time for selected filter; export const calculateTimeLeftForPostCheck = (firstPost: any) => { @@ -17,58 +15,50 @@ export const calculateTimeLeftForPostCheck = (firstPost: any) => { timeLeft = refetchTime; } return timeLeft; -} - +}; //filter posts that are not present in top 5 posts currently in list. export const filterLatestPosts = (fetchedPosts: any[], cachedPosts: any[]) => { - - console.log("Comparing: ", fetchedPosts, cachedPosts); + console.log('Comparing: ', fetchedPosts, cachedPosts); let latestPosts = []; fetchedPosts.forEach((post) => { const newPostAuthPrem = post.author + post.permlink; - const postExist = cachedPosts.find((cPost) => (cPost.author + post.permlink) === newPostAuthPrem); + const postExist = cachedPosts.find((cPost) => cPost.author + post.permlink === newPostAuthPrem); if (!postExist) { latestPosts.push(post); } }); - if (latestPosts.length > 0) { return latestPosts.slice(0, 5); - } else { return []; } }; - //process posts result and return updated posts for the list. export const getUpdatedPosts = ( prevPosts: any[], nextPosts: any[], shouldReset: boolean, tabMeta: TabMeta, - setTabMeta: (meta: TabMeta) => void + setTabMeta: (meta: TabMeta) => void, ) => { //return state as is if component is unmounter let _posts = nextPosts; - if (nextPosts.length === 0) { setTabMeta({ ...tabMeta, - isNoPost: true + isNoPost: true, }); return shouldReset ? [] : prevPosts; } - const refreshing = tabMeta.isRefreshing; - if (prevPosts.length > 0 && !shouldReset) { if (refreshing) { _posts = unionBy(_posts, prevPosts, 'permlink'); @@ -81,8 +71,7 @@ export const getUpdatedPosts = ( ...tabMeta, startAuthor: _posts[_posts.length - 1] && _posts[_posts.length - 1].author, startPermlink: _posts[_posts.length - 1] && _posts[_posts.length - 1].permlink, - }) - - return _posts -} + }); + return _posts; +}; diff --git a/src/components/tabbedPosts/services/tabbedPostsModels.ts b/src/components/tabbedPosts/services/tabbedPostsModels.ts index 2473c9225..7d848f105 100644 --- a/src/components/tabbedPosts/services/tabbedPostsModels.ts +++ b/src/components/tabbedPosts/services/tabbedPostsModels.ts @@ -1,63 +1,59 @@ - export interface TabbedPostsProps { - filterOptions:string[], - filterOptionsValue:string[], - isFeedScreen:boolean, - feedUsername:string, - selectedOptionIndex:number, - feedSubfilterOptions:string[], - feedSubfilterOptionsValue:string[], - getFor:string, - pageType:'main'|'community'|'profile'|'ownProfile', - tag:string, - forceLoadPosts:boolean, - tabContentOverrides:Map, - imagesToggleEnabled?:boolean, - stackedTabs:boolean, - pinnedPermlink?:string, - onTabChange:(index:number)=>void - handleOnScroll:()=>void, + filterOptions: string[]; + filterOptionsValue: string[]; + isFeedScreen: boolean; + feedUsername: string; + selectedOptionIndex: number; + feedSubfilterOptions: string[]; + feedSubfilterOptionsValue: string[]; + getFor: string; + pageType: 'main' | 'community' | 'profile' | 'ownProfile'; + tag: string; + forceLoadPosts: boolean; + tabContentOverrides: Map; + imagesToggleEnabled?: boolean; + stackedTabs: boolean; + pinnedPermlink?: string; + onTabChange: (index: number) => void; + handleOnScroll: () => void; } export interface TabMeta { - startPermlink:string, - startAuthor:string, - isLoading:boolean, - isRefreshing:boolean, - isNoPost:boolean, - } - - export interface LoadPostsOptions { - - filterKey:string; - prevPosts:any[]; - tabMeta:TabMeta; - setTabMeta:(meta:TabMeta)=>void, - getFor:string, - isConnected:boolean, - isLoggedIn:boolean, - feedUsername:string, - pinnedPermlink:string, - pageType:string, - tag:string, - nsfw:string, - isLatestPostsCheck?:boolean, - refreshing?:boolean, + startPermlink: string; + startAuthor: string; + isLoading: boolean; + isRefreshing: boolean; + isNoPost: boolean; +} - } +export interface LoadPostsOptions { + filterKey: string; + prevPosts: any[]; + tabMeta: TabMeta; + setTabMeta: (meta: TabMeta) => void; + getFor: string; + isConnected: boolean; + isLoggedIn: boolean; + feedUsername: string; + pinnedPermlink: string; + pageType: string; + tag: string; + nsfw: string; + isLatestPostsCheck?: boolean; + refreshing?: boolean; +} - - export interface TabContentProps { - filterKey:string, - isFeedScreen:boolean, - isInitialTab:boolean, - getFor:string, - pageType:'main'|'profile'|'ownProfile'|'community', - feedUsername:string, - tag:string, - forceLoadPosts:boolean, - filterScrollRequest:string, - pinnedPermlink?:string, - onScrollRequestProcessed:()=>void - handleOnScroll:()=>void; - } \ No newline at end of file +export interface TabContentProps { + filterKey: string; + isFeedScreen: boolean; + isInitialTab: boolean; + getFor: string; + pageType: 'main' | 'profile' | 'ownProfile' | 'community'; + feedUsername: string; + tag: string; + forceLoadPosts: boolean; + filterScrollRequest: string; + pinnedPermlink?: string; + onScrollRequestProcessed: () => void; + handleOnScroll: () => void; +} diff --git a/src/components/tabbedPosts/view/listEmptyView.tsx b/src/components/tabbedPosts/view/listEmptyView.tsx index 4c901a0ed..11e369986 100644 --- a/src/components/tabbedPosts/view/listEmptyView.tsx +++ b/src/components/tabbedPosts/view/listEmptyView.tsx @@ -1,30 +1,29 @@ -import React, {useEffect, useState} from 'react'; +import React, { useEffect, useState } from 'react'; import { useIntl } from 'react-intl'; import { get } from 'lodash'; import { Text, View, FlatList } from 'react-native'; +import { withNavigation } from '@react-navigation/compat'; +import { useSelector, useDispatch } from 'react-redux'; import { NoPost, PostCardPlaceHolder, UserListItem } from '../..'; import globalStyles from '../../../globalStyles'; import { CommunityListItem, EmptyScreen } from '../../basicUIElements'; import styles from './tabbedPostsStyles'; import { default as ROUTES } from '../../../constants/routeNames'; -import { withNavigation } from '@react-navigation/compat'; -import {useSelector, useDispatch } from 'react-redux'; -import { fetchCommunities, leaveCommunity, subscribeCommunity } from '../../../redux/actions/communitiesAction'; +import { + fetchCommunities, + leaveCommunity, + subscribeCommunity, +} from '../../../redux/actions/communitiesAction'; import { fetchLeaderboard, followUser, unfollowUser } from '../../../redux/actions/userAction'; import { getCommunity } from '../../../providers/hive/dhive'; interface TabEmptyViewProps { - filterKey:string, - isNoPost:boolean, - navigation:any, + filterKey: string; + isNoPost: boolean; + navigation: any; } -const TabEmptyView = ({ - filterKey, - isNoPost, - navigation, -}: TabEmptyViewProps) => { - +const TabEmptyView = ({ filterKey, isNoPost, navigation }: TabEmptyViewProps) => { const intl = useIntl(); const dispatch = useDispatch(); //redux properties @@ -43,23 +42,22 @@ const TabEmptyView = ({ //hooks - useEffect(()=>{ + useEffect(() => { if (isNoPost) { if (filterKey === 'friends') { if (recommendedUsers.length === 0) { _getRecommendedUsers(); } - } else if(filterKey === 'communities') { + } else if (filterKey === 'communities') { if (recommendedCommunities.length === 0) { _getRecommendedCommunities(); } } } - }, [isNoPost]) - + }, [isNoPost]); useEffect(() => { - const {loading, error, data} = leaderboard; + const { loading, error, data } = leaderboard; if (!loading) { if (!error && data && data.length > 0) { _formatRecommendedUsers(data); @@ -68,7 +66,7 @@ const TabEmptyView = ({ }, [leaderboard]); useEffect(() => { - const {loading, error, data} = communities; + const { loading, error, data } = communities; if (!loading) { if (!error && data && data?.length > 0) { _formatRecommendedCommunities(data); @@ -76,7 +74,6 @@ const TabEmptyView = ({ } }, [communities]); - useEffect(() => { const recommendeds = [...recommendedCommunities]; @@ -103,8 +100,6 @@ const TabEmptyView = ({ setRecommendedCommunities(recommendeds); }, [subscribingCommunities]); - - useEffect(() => { const recommendeds = [...recommendedUsers]; @@ -130,13 +125,12 @@ const TabEmptyView = ({ setRecommendedUsers(recommendeds); }, [followingUsers]); - //fetching const _getRecommendedUsers = () => dispatch(fetchLeaderboard()); const _getRecommendedCommunities = () => dispatch(fetchCommunities('', 10)); - //formating + //formating const _formatRecommendedCommunities = async (communitiesArray) => { try { const ecency = await getCommunity('hive-125125'); @@ -192,7 +186,6 @@ const TabEmptyView = ({ ); }; - const _handleFollowUserButtonPress = (data, isFollowing) => { let followAction; let successToastText = ''; @@ -223,14 +216,15 @@ const TabEmptyView = ({ dispatch(followAction(currentAccount, pinCode, data, successToastText, failToastText)); }; - const _handleOnPressLogin = () => { navigation.navigate(ROUTES.SCREENS.LOGIN); }; - -//render related operations - if ((filterKey === 'feed' || filterKey === 'friends' || filterKey === 'communities') && !isLoggedIn) { + //render related operations + if ( + (filterKey === 'feed' || filterKey === 'friends' || filterKey === 'communities') && + !isLoggedIn + ) { return ( - - {intl.formatMessage({ id: 'profile.follow_people' })} - - `${item._id || item.id}${index}`} - renderItem={({ item, index }) => ( - - navigation.navigate({ - routeName: ROUTES.SCREENS.PROFILE, - params: { - username, - }, - key: username, - }) - } - /> - )} - /> - - ); - } else if (filterKey === 'communities') { - return ( - <> - - {intl.formatMessage({ id: 'profile.follow_communities' })} - - `${item.id || item.title}${index}`} - renderItem={({ item, index }) => ( - - navigation.navigate({ - routeName: ROUTES.SCREENS.COMMUNITY, - params: { - tag: name, - }, - }) - } - handleSubscribeButtonPress={_handleSubscribeCommunityButtonPress} - isSubscribed={item.isSubscribed} - isLoadingRightAction={ - subscribingCommunities.hasOwnProperty(item.name) && - subscribingCommunities[item.name].loading - } - isLoggedIn={isLoggedIn} - /> - )} - /> - - ); - } else { return ( - - ) + <> + + {intl.formatMessage({ id: 'profile.follow_people' })} + + `${item._id || item.id}${index}`} + renderItem={({ item, index }) => ( + + navigation.navigate({ + routeName: ROUTES.SCREENS.PROFILE, + params: { + username, + }, + key: username, + }) + } + /> + )} + /> + + ); + } else if (filterKey === 'communities') { + return ( + <> + + {intl.formatMessage({ id: 'profile.follow_communities' })} + + `${item.id || item.title}${index}`} + renderItem={({ item, index }) => ( + + navigation.navigate({ + routeName: ROUTES.SCREENS.COMMUNITY, + params: { + tag: name, + }, + }) + } + handleSubscribeButtonPress={_handleSubscribeCommunityButtonPress} + isSubscribed={item.isSubscribed} + isLoadingRightAction={ + subscribingCommunities.hasOwnProperty(item.name) && + subscribingCommunities[item.name].loading + } + isLoggedIn={isLoggedIn} + /> + )} + /> + + ); + } else { + return ; } } @@ -342,4 +333,3 @@ const TabEmptyView = ({ }; export default withNavigation(TabEmptyView); - diff --git a/src/components/tabbedPosts/view/stackedTabBar.tsx b/src/components/tabbedPosts/view/stackedTabBar.tsx index eb924b568..4b0b04f30 100644 --- a/src/components/tabbedPosts/view/stackedTabBar.tsx +++ b/src/components/tabbedPosts/view/stackedTabBar.tsx @@ -1,119 +1,105 @@ -import React, { useRef, useState } from "react"; -import { useIntl } from "react-intl"; -import { useDispatch, useSelector } from "react-redux"; -import { CustomiseFiltersModal, FilterBar } from "../.."; -import { setHidePostsThumbnails } from "../../../redux/actions/applicationActions"; -import { CustomiseFiltersModalRef } from "../../customiseFiltersModal/customiseFiltersModal"; +import React, { useRef, useState } from 'react'; +import { useIntl } from 'react-intl'; +import { useDispatch, useSelector } from 'react-redux'; +import { CustomiseFiltersModal, FilterBar } from '../..'; +import { setHidePostsThumbnails } from '../../../redux/actions/applicationActions'; +import { CustomiseFiltersModalRef } from '../../customiseFiltersModal/customiseFiltersModal'; export interface TabItem { - filterKey:string; - label:string; + filterKey: string; + label: string; } interface StackedTabBarProps { - activeTab:boolean; - goToPage:(pageIndex)=>void; - tabs:string[]; - pageType?:'main'|'community'|'profile'|'ownProfile' - shouldStack:boolean; - firstStack:TabItem[]; - secondStack:TabItem[]; - initialFirstStackIndex:number; - onFilterSelect:(filterKey:string)=>void; - toggleHideImagesFlag:boolean; + activeTab: boolean; + goToPage: (pageIndex) => void; + tabs: string[]; + pageType?: 'main' | 'community' | 'profile' | 'ownProfile'; + shouldStack: boolean; + firstStack: TabItem[]; + secondStack: TabItem[]; + initialFirstStackIndex: number; + onFilterSelect: (filterKey: string) => void; + toggleHideImagesFlag: boolean; } export const StackedTabBar = ({ - goToPage, - tabs, - shouldStack, - firstStack, - secondStack, - initialFirstStackIndex, - onFilterSelect, - toggleHideImagesFlag, - pageType + goToPage, + tabs, + shouldStack, + firstStack, + secondStack, + initialFirstStackIndex, + onFilterSelect, + toggleHideImagesFlag, + pageType, +}: StackedTabBarProps) => { + const dispatch = useDispatch(); + const intl = useIntl(); -}:StackedTabBarProps) => { + const customiseModalRef = useRef(); - const dispatch = useDispatch(); - const intl = useIntl(); + //redux properties + const isHideImages = useSelector((state) => state.application.hidePostsThumbnails); - const customiseModalRef = useRef(); - - //redux properties - const isHideImages = useSelector((state) => state.application.hidePostsThumbnails); + const [selectedFilterIndex, setSelectedFilterIndex] = useState(initialFirstStackIndex); + const [selectedSecondStackIndex, setSelectedSecondStackIndex] = useState(0); - const [selectedFilterIndex, setSelectedFilterIndex] = useState(initialFirstStackIndex); - const [selectedSecondStackIndex, setSelectedSecondStackIndex] = useState(0); + const enableCustomTabs = pageType !== undefined; - const enableCustomTabs = pageType !== undefined; - - - const _onCustomisePress = () => { - if(customiseModalRef.current){ - customiseModalRef.current.show(); - } + const _onCustomisePress = () => { + if (customiseModalRef.current) { + customiseModalRef.current.show(); } + }; - const _onToggleImagesPress = () => { - dispatch(setHidePostsThumbnails(!isHideImages)) - } + const _onToggleImagesPress = () => { + dispatch(setHidePostsThumbnails(!isHideImages)); + }; - return ( - <> + return ( + <> { - return tabs[index] - ? tabs[index] - : intl.formatMessage({ id: item.label.toLowerCase() }).toUpperCase() - }) - } - + return tabs[index] + ? tabs[index] + : intl.formatMessage({ id: item.label.toLowerCase() }).toUpperCase(); + })} selectedOptionIndex={selectedFilterIndex} - rightIconName={toggleHideImagesFlag && "view-module"} - rightIconType={toggleHideImagesFlag && "MaterialIcons"} + rightIconName={toggleHideImagesFlag && 'view-module'} + rightIconType={toggleHideImagesFlag && 'MaterialIcons'} enableCustomiseButton={enableCustomTabs} onCustomisePress={_onCustomisePress} - onDropdownSelect={(index)=>{ + onDropdownSelect={(index) => { setSelectedFilterIndex(index); - if(index == 0 && shouldStack){ + if (index == 0 && shouldStack) { const tabIndex = firstStack.length + selectedSecondStackIndex; onFilterSelect(secondStack[selectedSecondStackIndex].filterKey); - goToPage(tabIndex) - }else{ + goToPage(tabIndex); + } else { onFilterSelect(firstStack[index].filterKey); goToPage(index); } - }} onRightIconPress={_onToggleImagesPress} /> - { - selectedFilterIndex == 0 && shouldStack && ( - - intl.formatMessage({ id: item.label.toLowerCase() }).toUpperCase(), - )} - selectedOptionIndex={selectedSecondStackIndex} - onDropdownSelect={(index)=>{ - setSelectedSecondStackIndex(index) - onFilterSelect(secondStack[index].filterKey); - goToPage(firstStack.length + index); - }} - /> - ) - } - - {enableCustomTabs && ( - + intl.formatMessage({ id: item.label.toLowerCase() }).toUpperCase(), + )} + selectedOptionIndex={selectedSecondStackIndex} + onDropdownSelect={(index) => { + setSelectedSecondStackIndex(index); + onFilterSelect(secondStack[index].filterKey); + goToPage(firstStack.length + index); + }} /> )} - - - ) - } \ No newline at end of file + + {enableCustomTabs && } + + ); +}; diff --git a/src/components/tabbedPosts/view/tabContent.tsx b/src/components/tabbedPosts/view/tabContent.tsx index 1258b54ee..69a41333e 100644 --- a/src/components/tabbedPosts/view/tabContent.tsx +++ b/src/components/tabbedPosts/view/tabContent.tsx @@ -1,30 +1,30 @@ -import React, {useState, useEffect, useRef} from 'react'; +import React, { useState, useEffect, useRef } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { AppState, NativeScrollEvent, NativeSyntheticEvent } from 'react-native'; +import { debounce } from 'lodash'; import PostsList from '../../postsList'; import { fetchPromotedEntries, loadPosts } from '../services/tabbedPostsFetch'; import { LoadPostsOptions, TabContentProps, TabMeta } from '../services/tabbedPostsModels'; -import {useSelector, useDispatch } from 'react-redux'; import TabEmptyView from './listEmptyView'; import { setInitPosts } from '../../../redux/actions/postsAction'; import { showReplyModal } from '../../../redux/actions/uiAction'; import { calculateTimeLeftForPostCheck } from '../services/tabbedPostsHelpers'; -import { AppState, NativeScrollEvent, NativeSyntheticEvent } from 'react-native'; import { PostsListRef } from '../../postsList/container/postsListContainer'; import ScrollTopPopup from './scrollTopPopup'; -import { debounce } from 'lodash'; const DEFAULT_TAB_META = { - startAuthor:'', - startPermlink:'', - isLoading:false, - isRefreshing:false, - } as TabMeta; + startAuthor: '', + startPermlink: '', + isLoading: false, + isRefreshing: false, +} as TabMeta; var scrollOffset = 0; var blockPopup = false; const SCROLL_POPUP_THRESHOLD = 5000; const TabContent = ({ - filterKey, + filterKey, isFeedScreen, isInitialTab, pageType, @@ -39,31 +39,29 @@ const TabContent = ({ }: TabContentProps) => { let _isMounted = true; - //redux properties const dispatch = useDispatch(); const isLoggedIn = useSelector((state) => state.application.isLoggedIn); const nsfw = useSelector((state) => state.application.nsfw); const isConnected = useSelector((state) => state.application.isConnected); const currentAccount = useSelector((state) => state.account.currentAccount); - const initPosts = useSelector((state) => state.posts.initPosts) + const initPosts = useSelector((state) => state.posts.initPosts); const username = currentAccount.username; const userPinned = currentAccount.about?.profile?.pinned; - //state const [posts, setPosts] = useState([]); const [promotedPosts, setPromotedPosts] = useState([]); const [sessionUser, setSessionUser] = useState(username); const [tabMeta, setTabMeta] = useState(DEFAULT_TAB_META); const [latestPosts, setLatestPosts] = useState([]); - const [postFetchTimer, setPostFetchTimer] = useState(0) + const [postFetchTimer, setPostFetchTimer] = useState(0); const [enableScrollTop, setEnableScrollTop] = useState(false); - const [curPinned, setCurPinned] = useState(pinnedPermlink) + const [curPinned, setCurPinned] = useState(pinnedPermlink); //refs - let postsListRef = useRef() + let postsListRef = useRef(); const appState = useRef(AppState.currentState); const postsRef = useRef(posts); const sessionUserRef = useRef(sessionUser); @@ -72,12 +70,8 @@ const TabContent = ({ postsRef.current = posts; sessionUserRef.current = sessionUser; - - - //side effects useEffect(() => { - if (isFeedScreen) { AppState.addEventListener('change', _handleAppStateChange); } @@ -85,295 +79,287 @@ const TabContent = ({ _initContent(true, feedUsername); return _cleanup; - }, [tag]) - - - useEffect(()=>{ - if(isConnected && (username !== sessionUser || forceLoadPosts)){ - _initContent(false, username); - } - }, [username, forceLoadPosts]) + }, [tag]); useEffect(() => { - if(filterScrollRequest && filterScrollRequest === filterKey){ + if (isConnected && (username !== sessionUser || forceLoadPosts)) { + _initContent(false, username); + } + }, [username, forceLoadPosts]); + + useEffect(() => { + if (filterScrollRequest && filterScrollRequest === filterKey) { _scrollToTop(); - if(onScrollRequestProcessed){ + if (onScrollRequestProcessed) { onScrollRequestProcessed(); } } - }, [filterScrollRequest]) + }, [filterScrollRequest]); - useEffect(()=>{ - console.log("curPinned change", userPinned); - if(pageType === 'ownProfile' && userPinned !== curPinned ){ + useEffect(() => { + console.log('curPinned change', userPinned); + if (pageType === 'ownProfile' && userPinned !== curPinned) { _scrollToTop(); - _loadPosts({shouldReset:true, _pinnedPermlink:userPinned}) + _loadPosts({ shouldReset: true, _pinnedPermlink: userPinned }); setCurPinned(userPinned); } - },[userPinned]) - + }, [userPinned]); const _cleanup = () => { _isMounted = false; - if(postFetchTimer){ + if (postFetchTimer) { clearTimeout(postFetchTimer); } if (isFeedScreen) { AppState.removeEventListener('change', _handleAppStateChange); } - } - - + }; //actions const _handleAppStateChange = (nextAppState) => { - if (appState.current.match(/inactive|background/) && nextAppState === 'active' && posts.length > 0) { + if ( + appState.current.match(/inactive|background/) && + nextAppState === 'active' && + posts.length > 0 + ) { const isLatestPostsCheck = true; _loadPosts({ - shouldReset:false, - isLatestPostsCheck + shouldReset: false, + isLatestPostsCheck, }); } appState.current = nextAppState; }; - - const _initContent = (isFirstCall = false, _feedUsername:string) => { + const _initContent = (isFirstCall = false, _feedUsername: string) => { _scrollToTop(); const initialPosts = isFirstCall && isFeedScreen && isInitialTab ? initPosts : []; setPosts(initialPosts); - setTabMeta(DEFAULT_TAB_META) + setTabMeta(DEFAULT_TAB_META); setSessionUser(_feedUsername); setLatestPosts([]); - if(postFetchTimer){ + if (postFetchTimer) { clearTimeout(postFetchTimer); } - if(username || (filterKey !== 'friends' && filterKey !== 'communities')){ + if (username || (filterKey !== 'friends' && filterKey !== 'communities')) { _loadPosts({ - shouldReset:!isFirstCall, + shouldReset: !isFirstCall, isFirstCall, - isLatestPostsCheck:false, - _feedUsername, - _posts:initialPosts, - _tabMeta:DEFAULT_TAB_META + isLatestPostsCheck: false, + _feedUsername, + _posts: initialPosts, + _tabMeta: DEFAULT_TAB_META, }); _getPromotedPosts(); } - } + }; //fetch posts from server const _loadPosts = async ({ shouldReset = false, isLatestPostsCheck = false, isFirstCall = false, - _feedUsername = isFeedScreen? sessionUserRef.current:feedUsername, + _feedUsername = isFeedScreen ? sessionUserRef.current : feedUsername, _posts = postsRef.current, _tabMeta = tabMeta, - _pinnedPermlink = curPinned - }:{ - shouldReset?:boolean; - isLatestPostsCheck?:boolean; - isFirstCall?:boolean; - _feedUsername?:string; - _posts?:any[]; - _tabMeta?:TabMeta; - _pinnedPermlink?:string + _pinnedPermlink = curPinned, + }: { + shouldReset?: boolean; + isLatestPostsCheck?: boolean; + isFirstCall?: boolean; + _feedUsername?: string; + _posts?: any[]; + _tabMeta?: TabMeta; + _pinnedPermlink?: string; }) => { const options = { - setTabMeta:(meta:TabMeta) => { - if(_isMounted){ - setTabMeta(meta) + setTabMeta: (meta: TabMeta) => { + if (_isMounted) { + setTabMeta(meta); } }, filterKey, - prevPosts:_posts, - tabMeta:_tabMeta, + prevPosts: _posts, + tabMeta: _tabMeta, isLoggedIn, nsfw, isConnected, isFeedScreen, - refreshing:shouldReset, + refreshing: shouldReset, pageType, isLatestPostsCheck, - feedUsername:_feedUsername, - pinnedPermlink:_pinnedPermlink, + feedUsername: _feedUsername, + pinnedPermlink: _pinnedPermlink, tag, - ...props - } as LoadPostsOptions + ...props, + } as LoadPostsOptions; - const result = await loadPosts(options) - if(_isMounted && result){ - if(shouldReset || isFirstCall){ + const result = await loadPosts(options); + if (_isMounted && result) { + if (shouldReset || isFirstCall) { setPosts([]); } - _postProcessLoadResult(result) + _postProcessLoadResult(result); } - } - + }; const _getPromotedPosts = async () => { - if(pageType === 'profile' || pageType === 'ownProfile' || pageType === 'community'){ + if (pageType === 'profile' || pageType === 'ownProfile' || pageType === 'community') { return; } - const pPosts = await fetchPromotedEntries(username) - if(pPosts){ - setPromotedPosts(pPosts) + const pPosts = await fetchPromotedEntries(username); + if (pPosts) { + setPromotedPosts(pPosts); } - } - - + }; //schedules post fetch - const _scheduleLatestPostsCheck = (firstPost:any) => { + const _scheduleLatestPostsCheck = (firstPost: any) => { if (firstPost) { if (postFetchTimer) { clearTimeout(postFetchTimer); } - const timeLeft = calculateTimeLeftForPostCheck(firstPost) + const timeLeft = calculateTimeLeftForPostCheck(firstPost); const _postFetchTimer = setTimeout(() => { - const isLatestPostsCheck = true; - _loadPosts({ - shouldReset:false, - isLatestPostsCheck - }); - }, - timeLeft - ); - setPostFetchTimer(_postFetchTimer) + const isLatestPostsCheck = true; + _loadPosts({ + shouldReset: false, + isLatestPostsCheck, + }); + }, timeLeft); + setPostFetchTimer(_postFetchTimer); } }; - //processes response from loadPost - const _postProcessLoadResult = ({updatedPosts, latestPosts}:any) => { + const _postProcessLoadResult = ({ updatedPosts, latestPosts }: any) => { //process new posts avatart - if(latestPosts && Array.isArray(latestPosts)){ - if(latestPosts.length > 0){ - setLatestPosts(latestPosts) - }else{ - _scheduleLatestPostsCheck(posts[0]) + if (latestPosts && Array.isArray(latestPosts)) { + if (latestPosts.length > 0) { + setLatestPosts(latestPosts); + } else { + _scheduleLatestPostsCheck(posts[0]); } } //process returned data - if(Array.isArray(updatedPosts)){ - if(updatedPosts.length){ + if (Array.isArray(updatedPosts)) { + if (updatedPosts.length) { //match new and old first post - const firstPostChanged = posts.length == 0 || (posts[0].permlink !== updatedPosts[0].permlink); + 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 - _scheduleLatestPostsCheck(updatedPosts[0]); + //schedule refetch of new posts by checking time of current post + _scheduleLatestPostsCheck(updatedPosts[0]); - if (isInitialTab) { - dispatch(setInitPosts(updatedPosts)); - } + if (isInitialTab) { + dispatch(setInitPosts(updatedPosts)); + } } - } else if (isFeedScreen && isInitialTab){ + } else if (isFeedScreen && isInitialTab) { //clear posts cache if no first tab posts available, precautionary measure for accoutn change - dispatch(setInitPosts([])) + dispatch(setInitPosts([])); } setPosts(updatedPosts); } - } + }; - - //view related routines const _onPostsPopupPress = () => { - _scrollToTop(); - _getPromotedPosts() - setPosts([...latestPosts, ...posts]) - _scheduleLatestPostsCheck(latestPosts[0]); - setLatestPosts([]); - } + _scrollToTop(); + _getPromotedPosts(); + setPosts([...latestPosts, ...posts]); + _scheduleLatestPostsCheck(latestPosts[0]); + setLatestPosts([]); + }; const _scrollToTop = () => { postsListRef.current.scrollToTop(); setEnableScrollTop(false); scrollPopupDebouce.cancel(); blockPopup = true; - setTimeout(()=>{ + setTimeout(() => { blockPopup = false; - }, 1000) + }, 1000); }; - const _handleOnScroll = () => { - if(handleOnScroll){ - handleOnScroll() + if (handleOnScroll) { + handleOnScroll(); } - } + }; //view rendereres const _renderEmptyContent = () => { - return - } + return ; + }; + const scrollPopupDebouce = debounce( + (value) => { + setEnableScrollTop(value); + }, + 500, + { leading: true }, + ); - const scrollPopupDebouce = debounce((value)=>{ - setEnableScrollTop(value); - }, 500, {leading:true}) - - const _onScroll = (event:NativeSyntheticEvent)=>{ + const _onScroll = (event: NativeSyntheticEvent) => { var currentOffset = event.nativeEvent.contentOffset.y; var scrollUp = currentOffset < scrollOffset; scrollOffset = currentOffset; - if(scrollUp && !blockPopup && currentOffset > SCROLL_POPUP_THRESHOLD){ - scrollPopupDebouce(true) + if (scrollUp && !blockPopup && currentOffset > SCROLL_POPUP_THRESHOLD) { + scrollPopupDebouce(true); } }; // show quick reply modal - const _showQuickReplyModal = (post:any) => { + const _showQuickReplyModal = (post: any) => { if (isLoggedIn) { - dispatch(showReplyModal(post)) + dispatch(showReplyModal(post)); } else { - //TODO: show proper alert message + //TODO: show proper alert message console.log('Not LoggedIn'); } - } + }; return ( - <> - { - _loadPosts({shouldReset}) - if(shouldReset){ - _getPromotedPosts() - } - }} - onScroll={_onScroll} - onScrollEndDrag={_handleOnScroll} - isRefreshing={tabMeta.isRefreshing} - isLoading={tabMeta.isLoading} - ListEmptyComponent={_renderEmptyContent} - pageType={pageType} - showQuickReplyModal={_showQuickReplyModal} - /> - post.avatar || '')} - enableScrollTop={enableScrollTop} - onPress={_onPostsPopupPress} - onClose={()=>{ - setLatestPosts([]) - setEnableScrollTop(false); - }} - /> - + { + _loadPosts({ shouldReset }); + if (shouldReset) { + _getPromotedPosts(); + } + }} + onScroll={_onScroll} + onScrollEndDrag={_handleOnScroll} + isRefreshing={tabMeta.isRefreshing} + isLoading={tabMeta.isLoading} + ListEmptyComponent={_renderEmptyContent} + pageType={pageType} + showQuickReplyModal={_showQuickReplyModal} + /> + post.avatar || '')} + enableScrollTop={enableScrollTop} + onPress={_onPostsPopupPress} + onClose={() => { + setLatestPosts([]); + setEnableScrollTop(false); + }} + /> + ); }; export default TabContent; - diff --git a/src/components/textInput/view/textInputView.tsx b/src/components/textInput/view/textInputView.tsx index 07b059f7e..d9a490eca 100644 --- a/src/components/textInput/view/textInputView.tsx +++ b/src/components/textInput/view/textInputView.tsx @@ -7,13 +7,13 @@ import { useAppSelector } from '../../../hooks'; import styles from './textInputStyles'; interface Props extends TextInputProps { - innerRef: Ref, - height: number, - style: TextStyle + innerRef: Ref; + height: number; + style: TextStyle; } const TextInputView = ({ innerRef, height, style, ...props }: Props) => { - const isDarkTheme = useAppSelector(state => state.application.isDarkTheme); + const isDarkTheme = useAppSelector((state) => state.application.isDarkTheme); return ( { {...props} style={[styles.input, { minHeight: height }, style]} /> - ) + ); }; export default TextInputView; diff --git a/src/components/transferAmountInputSection/transferAmountInputSectionStyles.ts b/src/components/transferAmountInputSection/transferAmountInputSectionStyles.ts index a8ea6c450..d3df54d9b 100644 --- a/src/components/transferAmountInputSection/transferAmountInputSectionStyles.ts +++ b/src/components/transferAmountInputSection/transferAmountInputSectionStyles.ts @@ -54,7 +54,7 @@ export default EStyleSheet.create({ textAlign: 'right', }, centerDescription: { - marginTop:8, + marginTop: 8, fontSize: 12, color: '$primaryBlack', fontWeight: '600', diff --git a/src/components/uploadsGalleryModal/children/uploadsGalleryContent.tsx b/src/components/uploadsGalleryModal/children/uploadsGalleryContent.tsx index e5345453a..f4855358e 100644 --- a/src/components/uploadsGalleryModal/children/uploadsGalleryContent.tsx +++ b/src/components/uploadsGalleryModal/children/uploadsGalleryContent.tsx @@ -2,13 +2,13 @@ import { proxifyImageSrc } from '@ecency/render-helper'; import React, { useEffect, useRef, useState } from 'react'; import { useIntl } from 'react-intl'; import { - ActivityIndicator, - Alert, - Keyboard, - Platform, - Text, - TouchableOpacity, - View, + ActivityIndicator, + Alert, + Keyboard, + Platform, + Text, + TouchableOpacity, + View, } from 'react-native'; import { View as AnimatedView } from 'react-native-animatable'; import Animated, { Easing } from 'react-native-reanimated'; @@ -18,312 +18,311 @@ import { FlatList } from 'react-native-gesture-handler'; import { Icon, IconButton } from '../..'; import { UploadedMedia } from '../../../models'; import styles, { - COMPACT_HEIGHT, - EXPANDED_HEIGHT, - MAX_HORIZONTAL_THUMBS, + COMPACT_HEIGHT, + EXPANDED_HEIGHT, + MAX_HORIZONTAL_THUMBS, } from './uploadsGalleryModalStyles'; import { useMediaDeleteMutation } from '../../../providers/queries'; type Props = { - insertedMediaUrls: string[]; - mediaUploads: any[]; - indices: Map; - isAddingToUploads: boolean; - getMediaUploads: () => void; - deleteMedia: (ids: string) => Promise; - insertMedia: (map: Map) => void; - handleOpenGallery: (addToUploads?: boolean) => void; - handleOpenCamera: () => void; - handleOpenForUpload: () => void; + insertedMediaUrls: string[]; + mediaUploads: any[]; + indices: Map; + isAddingToUploads: boolean; + getMediaUploads: () => void; + deleteMedia: (ids: string) => Promise; + insertMedia: (map: Map) => void; + handleOpenGallery: (addToUploads?: boolean) => void; + handleOpenCamera: () => void; + handleOpenForUpload: () => void; }; const UploadsGalleryContent = ({ - insertedMediaUrls, - mediaUploads, - isAddingToUploads, - getMediaUploads, - deleteMedia, - insertMedia, - handleOpenGallery, - handleOpenCamera, + insertedMediaUrls, + mediaUploads, + isAddingToUploads, + getMediaUploads, + deleteMedia, + insertMedia, + handleOpenGallery, + handleOpenCamera, }: Props) => { - const intl = useIntl(); + const intl = useIntl(); - const deleteMediaMutation = useMediaDeleteMutation(); + const deleteMediaMutation = useMediaDeleteMutation(); - const [deleteIds, setDeleteIds] = useState([]); - const [isDeleteMode, setIsDeleteMode] = useState(false); - const [isExpandedMode, setIsExpandedMode] = useState(false); + const [deleteIds, setDeleteIds] = useState([]); + const [isDeleteMode, setIsDeleteMode] = useState(false); + const [isExpandedMode, setIsExpandedMode] = useState(false); - const animatedHeightRef = useRef(new Animated.Value(COMPACT_HEIGHT)); + const animatedHeightRef = useRef(new Animated.Value(COMPACT_HEIGHT)); - const isDeleting = deleteMediaMutation.isLoading + const isDeleting = deleteMediaMutation.isLoading; - useEffect(() => { - if (isExpandedMode) { - Keyboard.dismiss(); - } - }, [isExpandedMode]); + useEffect(() => { + if (isExpandedMode) { + Keyboard.dismiss(); + } + }, [isExpandedMode]); - - const _deleteMedia = async () => { - deleteMediaMutation.mutate(deleteIds, { - onSettled: () => { - setIsDeleteMode(false); - setDeleteIds([]); - } - }); - }; + const _deleteMedia = async () => { + deleteMediaMutation.mutate(deleteIds, { + onSettled: () => { + setIsDeleteMode(false); + setDeleteIds([]); + }, + }); + }; - const _onDeletePress = async () => { - if (isDeleteMode && deleteIds.length > 0) { - const _onCancelPress = () => { - setIsDeleteMode(false); - setDeleteIds([]); - }; + const _onDeletePress = async () => { + if (isDeleteMode && deleteIds.length > 0) { + const _onCancelPress = () => { + setIsDeleteMode(false); + setDeleteIds([]); + }; - Alert.alert( - intl.formatMessage({ id: 'alert.delete' }), - intl.formatMessage({ id: 'uploads_modal.confirm_delete' }), - [ - { - text: intl.formatMessage({ id: 'alert.cancel' }), - style: 'cancel', - onPress: _onCancelPress, - }, - { - text: intl.formatMessage({ id: 'alert.confirm' }), - onPress: () => _deleteMedia(), - }, - ], - ); + Alert.alert( + intl.formatMessage({ id: 'alert.delete' }), + intl.formatMessage({ id: 'uploads_modal.confirm_delete' }), + [ + { + text: intl.formatMessage({ id: 'alert.cancel' }), + style: 'cancel', + onPress: _onCancelPress, + }, + { + text: intl.formatMessage({ id: 'alert.confirm' }), + onPress: () => _deleteMedia(), + }, + ], + ); + } else { + setIsDeleteMode(!isDeleteMode); + } + }; + + //render list item for snippet and handle actions; + const _renderItem = ({ item, index }: { item: UploadedMedia; index: number }) => { + const _onPress = () => { + if (isDeleteMode) { + const idIndex = deleteIds.indexOf(item._id); + if (idIndex >= 0) { + deleteIds.splice(idIndex, 1); } else { - setIsDeleteMode(!isDeleteMode); + deleteIds.push(item._id); } + setDeleteIds([...deleteIds]); + } else { + insertMedia(new Map([[index, true]])); + } }; - //render list item for snippet and handle actions; - const _renderItem = ({ item, index }: { item: UploadedMedia; index: number }) => { - const _onPress = () => { - if (isDeleteMode) { - const idIndex = deleteIds.indexOf(item._id); - if (idIndex >= 0) { - deleteIds.splice(idIndex, 1); - } else { - deleteIds.push(item._id); - } - setDeleteIds([...deleteIds]); - } else { - insertMedia(new Map([[index, true]])); - } - }; - - const thumbUrl = proxifyImageSrc(item.url, 600, 500, Platform.OS === 'ios' ? 'match' : 'webp'); - let isInsertedTimes = 0; - insertedMediaUrls.forEach((url) => (isInsertedTimes += url === item.url ? 1 : 0)); - const isToBeDeleted = deleteIds.indexOf(item._id) >= 0; - const transformStyle = { - transform: isToBeDeleted ? [{ scaleX: 0.7 }, { scaleY: 0.7 }] : [], - }; - - const _renderMinus = () => - isDeleteMode && ( - - - - ); - - const _renderCounter = () => - isInsertedTimes > 0 && - !isDeleteMode && ( - - {isInsertedTimes} - - ); - - return ( - - - - {_renderCounter()} - {_renderMinus()} - - - ); + const thumbUrl = proxifyImageSrc(item.url, 600, 500, Platform.OS === 'ios' ? 'match' : 'webp'); + let isInsertedTimes = 0; + insertedMediaUrls.forEach((url) => (isInsertedTimes += url === item.url ? 1 : 0)); + const isToBeDeleted = deleteIds.indexOf(item._id) >= 0; + const transformStyle = { + transform: isToBeDeleted ? [{ scaleX: 0.7 }, { scaleY: 0.7 }] : [], }; - const _renderSelectButton = (iconName: string, text: string, onPress: () => void) => { - return ( - { - onPress && onPress(); - }} - > - - - - - - - - {text} - - - ); - }; - - const _renderHeaderContent = () => ( - - - {_renderSelectButton('image', 'Gallery', handleOpenGallery)} - {_renderSelectButton('camera', 'Camera', handleOpenCamera)} - - - { - handleOpenGallery(true); - }} - /> - { - setIsDeleteMode(!isDeleteMode); - setDeleteIds([]); - }} - /> - - - {isAddingToUploads && ( - - - - )} - - {isExpandedMode && _renderExpansionButton()} - {isExpandedMode && _renderDeleteButton()} - - ); - - //render empty list placeholder - const _renderEmptyContent = () => { - return ( - <> - - {intl.formatMessage({ id: 'uploads_modal.label_no_images' })} - - - ); - }; - - const _renderExpansionButton = () => ( - + isDeleteMode && ( + + { - Animated.timing(animatedHeightRef.current, { - toValue: isExpandedMode ? COMPACT_HEIGHT : EXPANDED_HEIGHT, - duration: 300, - easing: Easing.inOut(Easing.cubic), - }).start(() => { - setIsExpandedMode(!isExpandedMode); - }); - }} - /> - ); + name="minus" + size={20} + /> + + ); - const _renderDeleteButton = () => { - if (deleteIds.length > 0) { - return isExpandedMode ? ( - 0 ? '$primaryBlack' : '$primaryBlack')} - size={32} - onPress={_onDeletePress} - isLoading={isDeleting} - /> - ) : ( - 0 ? 'slideInRight' : 'slideOutRight'} - duration={300} - style={styles.deleteButtonContainer} - > - - - ); - } - return null; - }; + const _renderCounter = () => + isInsertedTimes > 0 && + !isDeleteMode && ( + + {isInsertedTimes} + + ); return ( - - `item_${item.url}`} - renderItem={_renderItem} - style={{ flex: 1 }} - contentContainerStyle={ - isExpandedMode ? styles.gridContentContainer : styles.listContentContainer - } - ListHeaderComponent={_renderHeaderContent} - ListEmptyComponent={_renderEmptyContent} - ListFooterComponent={!isExpandedMode && mediaUploads.length > 0 && _renderExpansionButton} - extraData={deleteIds} - horizontal={!isExpandedMode} - numColumns={isExpandedMode ? 2 : 1} - keyboardShouldPersistTaps="always" - /> - - {!isExpandedMode && _renderDeleteButton()} - + + + + {_renderCounter()} + {_renderMinus()} + + ); + }; + + const _renderSelectButton = (iconName: string, text: string, onPress: () => void) => { + return ( + { + onPress && onPress(); + }} + > + + + + + + + + {text} + + + ); + }; + + const _renderHeaderContent = () => ( + + + {_renderSelectButton('image', 'Gallery', handleOpenGallery)} + {_renderSelectButton('camera', 'Camera', handleOpenCamera)} + + + { + handleOpenGallery(true); + }} + /> + { + setIsDeleteMode(!isDeleteMode); + setDeleteIds([]); + }} + /> + + + {isAddingToUploads && ( + + + + )} + + {isExpandedMode && _renderExpansionButton()} + {isExpandedMode && _renderDeleteButton()} + + ); + + //render empty list placeholder + const _renderEmptyContent = () => { + return ( + <> + + {intl.formatMessage({ id: 'uploads_modal.label_no_images' })} + + + ); + }; + + const _renderExpansionButton = () => ( + { + Animated.timing(animatedHeightRef.current, { + toValue: isExpandedMode ? COMPACT_HEIGHT : EXPANDED_HEIGHT, + duration: 300, + easing: Easing.inOut(Easing.cubic), + }).start(() => { + setIsExpandedMode(!isExpandedMode); + }); + }} + /> + ); + + const _renderDeleteButton = () => { + if (deleteIds.length > 0) { + return isExpandedMode ? ( + 0 ? '$primaryBlack' : '$primaryBlack')} + size={32} + onPress={_onDeletePress} + isLoading={isDeleting} + /> + ) : ( + 0 ? 'slideInRight' : 'slideOutRight'} + duration={300} + style={styles.deleteButtonContainer} + > + + + ); + } + return null; + }; + + return ( + + `item_${item.url}`} + renderItem={_renderItem} + style={{ flex: 1 }} + contentContainerStyle={ + isExpandedMode ? styles.gridContentContainer : styles.listContentContainer + } + ListHeaderComponent={_renderHeaderContent} + ListEmptyComponent={_renderEmptyContent} + ListFooterComponent={!isExpandedMode && mediaUploads.length > 0 && _renderExpansionButton} + extraData={deleteIds} + horizontal={!isExpandedMode} + numColumns={isExpandedMode ? 2 : 1} + keyboardShouldPersistTaps="always" + /> + + {!isExpandedMode && _renderDeleteButton()} + + ); }; export default UploadsGalleryContent; diff --git a/src/components/uploadsGalleryModal/children/uploadsGalleryModalStyles.ts b/src/components/uploadsGalleryModal/children/uploadsGalleryModalStyles.ts index 845f39d41..95c043a53 100644 --- a/src/components/uploadsGalleryModal/children/uploadsGalleryModalStyles.ts +++ b/src/components/uploadsGalleryModal/children/uploadsGalleryModalStyles.ts @@ -15,7 +15,7 @@ export default EStyleSheet.create({ }, listContentContainer: { - marginTop:8, + marginTop: 8, paddingRight: 72, paddingLeft: 16, }, @@ -30,7 +30,7 @@ export default EStyleSheet.create({ height: THUMB_SIZE, width: THUMB_SIZE, borderRadius: 16, - backgroundColor: '$primaryLightGray' + backgroundColor: '$primaryLightGray', } as ImageStyle, gridMediaItem: { @@ -39,11 +39,11 @@ export default EStyleSheet.create({ width: GRID_THUMB_SIZE, marginVertical: 8, borderRadius: 16, - backgroundColor: '$primaryLightGray' + backgroundColor: '$primaryLightGray', } as ImageStyle, inputContainer: { - flex: 1 + flex: 1, } as ViewStyle, titleInput: { color: '$primaryBlack', @@ -53,7 +53,7 @@ export default EStyleSheet.create({ paddingVertical: 0, backgroundColor: '$primaryBackgroundColor', borderBottomWidth: StyleSheet.hairlineWidth, - borderBottomColor: '$primaryDarkGray' + borderBottomColor: '$primaryDarkGray', } as TextStyle, title: { @@ -69,20 +69,19 @@ export default EStyleSheet.create({ fontSize: 16, color: '$primaryBlack', marginLeft: 12, - alignSelf:'center' + alignSelf: 'center', }, btnText: { - color: '$pureWhite' + color: '$pureWhite', } as TextStyle, saveButton: { - backgroundColor: '$primaryBlue', width: 150, paddingVertical: 16, borderRadius: 32, justifyContent: 'center', - alignItems: 'center' + alignItems: 'center', } as ViewStyle, closeButton: { @@ -90,14 +89,14 @@ export default EStyleSheet.create({ paddingVertical: 8, borderRadius: 16, justifyContent: 'center', - alignItems: 'center' + alignItems: 'center', } as ViewStyle, actionPanel: { flexDirection: 'row', justifyContent: 'flex-end', alignItems: 'center', - marginBottom: 16 + marginBottom: 16, } as ViewStyle, itemIcon: { @@ -113,8 +112,8 @@ export default EStyleSheet.create({ selectButtonsContainer: { justifyContent: 'space-around', paddingVertical: 8, - marginRight:8, - height: THUMB_SIZE + marginRight: 8, + height: THUMB_SIZE, } as ViewStyle, selectButton: { @@ -128,14 +127,14 @@ export default EStyleSheet.create({ marginTop: -16, zIndex: 2, borderRadius: 12, - backgroundColor: "$primaryBlack" + backgroundColor: '$primaryBlack', } as ViewStyle, selectButtonLabel: { fontSize: 16, textAlignVertical: 'top', color: '$primaryBlack', - marginLeft: 4 + marginLeft: 4, } as TextStyle, pillBtnContainer: { @@ -153,16 +152,15 @@ export default EStyleSheet.create({ width: THUMB_SIZE / 1.8, borderRadius: 0, borderBottomLeftRadius: 20, - borderBottomRightRadius: 20 + borderBottomRightRadius: 20, } as ViewStyle, - deleteButtonContainer: { position: 'absolute', right: 0, top: 0, bottom: 0, - justifyContent: 'center' + justifyContent: 'center', }, deleteButton: { @@ -171,14 +169,13 @@ export default EStyleSheet.create({ borderRadius: 0, borderBottomLeftRadius: 20, borderTopLeftRadius: 20, - backgroundColor: '$primaryRed' + backgroundColor: '$primaryRed', } as ViewStyle, itemIconWrapper: { justifyContent: 'center', alignItems: 'center', backgroundColor: '$primaryRed', - } as ViewStyle, minusContainer: { @@ -200,15 +197,14 @@ export default EStyleSheet.create({ height: 24, width: 24, justifyContent: 'center', - alignItems: 'center' + alignItems: 'center', } as ViewStyle, counterText: { color: '$primaryBlack', - fontSize: 16 + fontSize: 16, } as TextStyle, - checkStyle: { backgroundColor: '$white', } as ViewStyle, @@ -224,7 +220,6 @@ export default EStyleSheet.create({ marginLeft: 8, borderRadius: 20, justifyContent: 'center', - alignItems: 'center' - } as ViewStyle - -}) + alignItems: 'center', + } as ViewStyle, +}); diff --git a/src/components/uploadsGalleryModal/container/uploadsGalleryModal.tsx b/src/components/uploadsGalleryModal/container/uploadsGalleryModal.tsx index 631f12464..ef2226738 100644 --- a/src/components/uploadsGalleryModal/container/uploadsGalleryModal.tsx +++ b/src/components/uploadsGalleryModal/container/uploadsGalleryModal.tsx @@ -12,339 +12,341 @@ import showLoginAlert from '../../../utils/showLoginAlert'; import { useMediaQuery, useMediaUploadMutation } from '../../../providers/queries'; export interface UploadsGalleryModalRef { - showModal: () => void; + showModal: () => void; } export enum MediaInsertStatus { - UPLOADING = 'UPLOADING', - READY = 'READY', - FAILED = 'FAILED', + UPLOADING = 'UPLOADING', + READY = 'READY', + FAILED = 'FAILED', } export interface MediaInsertData { - url: string; - filename?: string; - text: string; - status: MediaInsertStatus; + url: string; + filename?: string; + text: string; + status: MediaInsertStatus; } interface UploadsGalleryModalProps { - insertedMediaUrls: string[]; - paramFiles: any[]; - username: string; - isEditing: boolean; - isPreviewActive: boolean; - hideToolbarExtension: () => void; - handleMediaInsert: (data: Array) => void; - setIsUploading: (status: boolean) => void; + insertedMediaUrls: string[]; + paramFiles: any[]; + username: string; + isEditing: boolean; + isPreviewActive: boolean; + hideToolbarExtension: () => void; + handleMediaInsert: (data: Array) => void; + setIsUploading: (status: boolean) => void; } export const UploadsGalleryModal = forwardRef( - ( - { - insertedMediaUrls, - paramFiles, - username, - isEditing, - isPreviewActive, - hideToolbarExtension, - handleMediaInsert, - setIsUploading, - }: UploadsGalleryModalProps, - ref, - ) => { - const intl = useIntl(); - const dispatch = useAppDispatch(); + ( + { + insertedMediaUrls, + paramFiles, + username, + isEditing, + isPreviewActive, + hideToolbarExtension, + handleMediaInsert, + setIsUploading, + }: UploadsGalleryModalProps, + ref, + ) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); - const mediaQuery = useMediaQuery(); - const mediaUploadMutation = useMediaUploadMutation(); + const mediaQuery = useMediaQuery(); + const mediaUploadMutation = useMediaUploadMutation(); - const pendingInserts = useRef([]); + const pendingInserts = useRef([]); - const [mediaUploads, setMediaUploads] = useState([]); - const [showModal, setShowModal] = useState(false); - const [isAddingToUploads, setIsAddingToUploads] = useState(false); + const [mediaUploads, setMediaUploads] = useState([]); + const [showModal, setShowModal] = useState(false); + const [isAddingToUploads, setIsAddingToUploads] = useState(false); - const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn); - const pinCode = useAppSelector((state) => state.application.pin); - const currentAccount = useAppSelector((state) => state.account.currentAccount); + const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn); + const pinCode = useAppSelector((state) => state.application.pin); + const currentAccount = useAppSelector((state) => state.account.currentAccount); - useImperativeHandle(ref, () => ({ - toggleModal: (value: boolean) => { - if (!isLoggedIn) { - showLoginAlert({ intl }); - return; - } + useImperativeHandle(ref, () => ({ + toggleModal: (value: boolean) => { + if (!isLoggedIn) { + showLoginAlert({ intl }); + return; + } - if (value === showModal) { - return; - } + if (value === showModal) { + return; + } - if (value) { - _getMediaUploads(); - } - setShowModal(value); + if (value) { + _getMediaUploads(); + } + setShowModal(value); + }, + })); + + useEffect(() => { + if (paramFiles) { + console.log('files : ', paramFiles); + + //delay is a workaround to let editor ready before initiating uploads on mount + delay(500).then(() => { + const _mediaItems = paramFiles.map((el) => { + if (el.filePath && el.fileName) { + const _media = { + path: el.filePath, + mime: el.mimeType, + filename: el.fileName, + }; + + return _media; + } + return null; + }); + + _handleMediaOnSelected(_mediaItems, true); + }); + } + }, [paramFiles]); + + useEffect(() => { + if (!isEditing && pendingInserts.current.length) { + handleMediaInsert(pendingInserts.current); + pendingInserts.current = []; + } + }, [isEditing]); + + const _handleOpenImagePicker = (addToUploads?: boolean) => { + ImagePicker.openPicker({ + includeBase64: true, + multiple: true, + mediaType: 'photo', + smartAlbums: ['UserLibrary', 'Favorites', 'PhotoStream', 'Panoramas', 'Bursts'], + }) + .then((images) => { + if (images && !Array.isArray(images)) { + images = [images]; + } + _handleMediaOnSelected(images, !addToUploads); + }) + .catch((e) => { + _handleMediaOnSelectFailure(e); + }); + }; + + const _handleOpenCamera = () => { + ImagePicker.openCamera({ + includeBase64: true, + mediaType: 'photo', + }) + .then((image) => { + _handleMediaOnSelected([image], true); + }) + .catch((e) => { + _handleMediaOnSelectFailure(e); + }); + }; + + const _handleMediaOnSelected = async (media: Image[], shouldInsert: boolean) => { + try { + if (!media || media.length == 0) { + throw new Error('New media items returned'); + } + + if (shouldInsert) { + setShowModal(false); + hideToolbarExtension(); + media.forEach((element, index) => { + if (element) { + media[index].filename = + element.filename || + extractFilenameFromPath({ path: element.path, mimeType: element.mime }); + handleMediaInsert([ + { + filename: element.filename, + url: '', + text: '', + status: MediaInsertStatus.UPLOADING, + }, + ]); + } + }); + } + + for (let index = 0; index < media.length; index++) { + const element = media[index]; + if (element) { + await _uploadImage(element, { shouldInsert }); + } + } + } catch (error) { + console.log('Failed to upload image', error); + + bugsnapInstance.notify(error); + } + }; + + const _uploadImage = async (media, { shouldInsert } = { shouldInsert: false }) => { + if (!isLoggedIn) return; + try { + if (setIsUploading) { + setIsUploading(true); + } + if (!shouldInsert) { + setIsAddingToUploads(true); + } + + await mediaUploadMutation.mutateAsync( + { + media, + addToUploads: !shouldInsert, + }, + { + onSuccess: (data) => { + console.log('upload successfully', data, media, shouldInsert); + if (data && data.url && shouldInsert) { + _handleMediaInsertion({ + filename: media.filename, + url: data.url, + text: '', + status: MediaInsertStatus.READY, + }); + } }, - })); - - useEffect(() => { - if (paramFiles) { - console.log('files : ', paramFiles); - - //delay is a workaround to let editor ready before initiating uploads on mount - delay(500).then(() => { - const _mediaItems = paramFiles.map((el) => { - if (el.filePath && el.fileName) { - const _media = { - path: el.filePath, - mime: el.mimeType, - filename: el.fileName, - }; - - return _media; - } - return null; - }); - - _handleMediaOnSelected(_mediaItems, true); - }); - } - }, [paramFiles]); - - useEffect(() => { - if (!isEditing && pendingInserts.current.length) { - handleMediaInsert(pendingInserts.current); - pendingInserts.current = []; - } - }, [isEditing]); - - const _handleOpenImagePicker = (addToUploads?: boolean) => { - ImagePicker.openPicker({ - includeBase64: true, - multiple: true, - mediaType: 'photo', - smartAlbums: ['UserLibrary', 'Favorites', 'PhotoStream', 'Panoramas', 'Bursts'], - }) - .then((images) => { - if (images && !Array.isArray(images)) { - images = [images]; - } - _handleMediaOnSelected(images, !addToUploads); - }) - .catch((e) => { - _handleMediaOnSelectFailure(e); - }); - }; - - const _handleOpenCamera = () => { - ImagePicker.openCamera({ - includeBase64: true, - mediaType: 'photo', - }) - .then((image) => { - _handleMediaOnSelected([image], true); - }) - .catch((e) => { - _handleMediaOnSelectFailure(e); - }); - }; - - const _handleMediaOnSelected = async (media: Image[], shouldInsert: boolean) => { - try { - if (!media || media.length == 0) { - throw new Error('New media items returned'); - } - - if (shouldInsert) { - setShowModal(false); - hideToolbarExtension(); - media.forEach((element, index) => { - if (element) { - media[index].filename = - element.filename || - extractFilenameFromPath({ path: element.path, mimeType: element.mime }); - handleMediaInsert([ - { - filename: element.filename, - url: '', - text: '', - status: MediaInsertStatus.UPLOADING, - }, - ]); - } - }); - } - - for (let index = 0; index < media.length; index++) { - const element = media[index]; - if (element) { - await _uploadImage(element, { shouldInsert }); - } - } - } catch (error) { - console.log('Failed to upload image', error); - - bugsnapInstance.notify(error); - } - }; - - const _uploadImage = async (media, { shouldInsert } = { shouldInsert: false }) => { - if (!isLoggedIn) return; - try { - if (setIsUploading) { - setIsUploading(true); - } - if (!shouldInsert) { - setIsAddingToUploads(true); - } - - await mediaUploadMutation.mutateAsync({ - media, - addToUploads: !shouldInsert - }, { - onSuccess: (data) => { - console.log('upload successfully', data, media, shouldInsert) - if (data && data.url && shouldInsert) { - _handleMediaInsertion({ - filename: media.filename, - url: data.url, - text: '', - status: MediaInsertStatus.READY, - }); - } - }, - onSettled: () => { - if (setIsUploading) { - setIsUploading(false); - } - setIsAddingToUploads(false); - }, - onError: (err) => { throw err }, - }) - - } catch (error) { - console.log('error while uploading image : ', error); - - if (error.toString().includes('code 413')) { - Alert.alert( - intl.formatMessage({ - id: 'alert.fail', - }), - intl.formatMessage({ - id: 'alert.payloadTooLarge', - }), - ); - } else if (error.toString().includes('code 429')) { - Alert.alert( - intl.formatMessage({ - id: 'alert.fail', - }), - intl.formatMessage({ - id: 'alert.quotaExceeded', - }), - ); - } else if (error.toString().includes('code 400')) { - Alert.alert( - intl.formatMessage({ - id: 'alert.fail', - }), - intl.formatMessage({ - id: 'alert.invalidImage', - }), - ); - } else { - Alert.alert( - intl.formatMessage({ - id: 'alert.fail', - }), - error.message || error.toString(), - ); - } - - if (shouldInsert) { - _handleMediaInsertion({ - filename: media.filename, - url: '', - text: '', - status: MediaInsertStatus.FAILED, - }); - } - } - }; - - const _handleMediaOnSelectFailure = (error) => { - if (error.code === 'E_PERMISSION_MISSING') { - Alert.alert( - intl.formatMessage({ - id: 'alert.permission_denied', - }), - intl.formatMessage({ - id: 'alert.permission_text', - }), - ); - } else { - Alert.alert( - intl.formatMessage({ - id: 'alert.fail', - }), - error.message || JSON.stringify(error), - ); - } - }; - - const _handleMediaInsertion = (data: MediaInsertData) => { - if (isEditing) { - pendingInserts.current.push(data); - } else if (handleMediaInsert) { - handleMediaInsert([data]); - } - }; - - - - //fetch images from server - const _getMediaUploads = async () => { - try { - if (username) { - console.log('getting images for: ' + username); - const images = await getImages(); - console.log('images received', images); - setMediaUploads(images || []); - } - } catch (err) { - console.warn('Failed to get images'); - } - setIsAddingToUploads(false); - }; - - //inserts media items in post body - const _insertMedia = async (map: Map) => { - const data: MediaInsertData[] = []; - for (const index of map.keys()) { - console.log(index); - const item = mediaUploads[index]; - data.push({ - url: item.url, - text: '', - status: MediaInsertStatus.READY, - }); - } - handleMediaInsert(data); - }; - - return ( - !isPreviewActive && - showModal && ( - - ) + onSettled: () => { + if (setIsUploading) { + setIsUploading(false); + } + setIsAddingToUploads(false); + }, + onError: (err) => { + throw err; + }, + }, ); - }, + } catch (error) { + console.log('error while uploading image : ', error); + + if (error.toString().includes('code 413')) { + Alert.alert( + intl.formatMessage({ + id: 'alert.fail', + }), + intl.formatMessage({ + id: 'alert.payloadTooLarge', + }), + ); + } else if (error.toString().includes('code 429')) { + Alert.alert( + intl.formatMessage({ + id: 'alert.fail', + }), + intl.formatMessage({ + id: 'alert.quotaExceeded', + }), + ); + } else if (error.toString().includes('code 400')) { + Alert.alert( + intl.formatMessage({ + id: 'alert.fail', + }), + intl.formatMessage({ + id: 'alert.invalidImage', + }), + ); + } else { + Alert.alert( + intl.formatMessage({ + id: 'alert.fail', + }), + error.message || error.toString(), + ); + } + + if (shouldInsert) { + _handleMediaInsertion({ + filename: media.filename, + url: '', + text: '', + status: MediaInsertStatus.FAILED, + }); + } + } + }; + + const _handleMediaOnSelectFailure = (error) => { + if (error.code === 'E_PERMISSION_MISSING') { + Alert.alert( + intl.formatMessage({ + id: 'alert.permission_denied', + }), + intl.formatMessage({ + id: 'alert.permission_text', + }), + ); + } else { + Alert.alert( + intl.formatMessage({ + id: 'alert.fail', + }), + error.message || JSON.stringify(error), + ); + } + }; + + const _handleMediaInsertion = (data: MediaInsertData) => { + if (isEditing) { + pendingInserts.current.push(data); + } else if (handleMediaInsert) { + handleMediaInsert([data]); + } + }; + + //fetch images from server + const _getMediaUploads = async () => { + try { + if (username) { + console.log('getting images for: ' + username); + const images = await getImages(); + console.log('images received', images); + setMediaUploads(images || []); + } + } catch (err) { + console.warn('Failed to get images'); + } + setIsAddingToUploads(false); + }; + + //inserts media items in post body + const _insertMedia = async (map: Map) => { + const data: MediaInsertData[] = []; + for (const index of map.keys()) { + console.log(index); + const item = mediaUploads[index]; + data.push({ + url: item.url, + text: '', + status: MediaInsertStatus.READY, + }); + } + handleMediaInsert(data); + }; + + return ( + !isPreviewActive && + showModal && ( + + ) + ); + }, ); diff --git a/src/components/upvote/view/upvoteView.tsx b/src/components/upvote/view/upvoteView.tsx index 6495a8c8a..14f1dd3c3 100644 --- a/src/components/upvote/view/upvoteView.tsx +++ b/src/components/upvote/view/upvoteView.tsx @@ -140,8 +140,8 @@ const UpvoteView = ({ //record user points userActivityMutation.mutate({ pointsTy: PointActivityIds.VOTE, - transactionId: response.id - }) + transactionId: response.id, + }); if (!response || !response.id) { Alert.alert( @@ -214,8 +214,8 @@ const UpvoteView = ({ //record usr points userActivityMutation.mutate({ pointsTy: PointActivityIds.VOTE, - transactionId: response.id - }) + transactionId: response.id, + }); setUpvote(!!sliderValue); setIsVoting(false); onVote(amount, true); diff --git a/src/config/coingeckoApi.ts b/src/config/coingeckoApi.ts index 9cb8534e3..d4264d121 100644 --- a/src/config/coingeckoApi.ts +++ b/src/config/coingeckoApi.ts @@ -8,5 +8,4 @@ const coingeckoApi = axios.create({ baseURL: `${BASE_URL}/${PATH_API}/${API_VERSION}`, }); - -export default coingeckoApi; \ No newline at end of file +export default coingeckoApi; diff --git a/src/config/ecencyApi.ts b/src/config/ecencyApi.ts index c58b89376..7e6f78231 100644 --- a/src/config/ecencyApi.ts +++ b/src/config/ecencyApi.ts @@ -5,7 +5,7 @@ import { get } from 'lodash'; import { store } from '../redux/store/store'; import { getDigitPinCode } from '../providers/hive/dhive'; import { decryptKey } from '../utils/crypto'; -import bugsnagInstance from '../config/bugsnag'; +import bugsnagInstance from './bugsnag'; const api = axios.create({ baseURL: Config.ECENCY_BACKEND_API, @@ -19,16 +19,17 @@ api.interceptors.request.use((request) => { console.log('Starting ecency Request', request); //skip code addition is register and token refresh endpoint is triggered - if (request.url === '/private-api/account-create' - || request.url === '/auth-api/hs-token-refresh' - || request.url === '/private-api/promoted-entries' - || request.url.startsWith('private-api/leaderboard') - || request.url.startsWith('/private-api/received-vesting/') - || request.url.startsWith('/private-api/referrals/') - || request.url.startsWith('/private-api/market-data') - || request.url.startsWith('/private-api/comment-history') + if ( + request.url === '/private-api/account-create' || + request.url === '/auth-api/hs-token-refresh' || + request.url === '/private-api/promoted-entries' || + request.url.startsWith('private-api/leaderboard') || + request.url.startsWith('/private-api/received-vesting/') || + request.url.startsWith('/private-api/referrals/') || + request.url.startsWith('/private-api/market-data') || + request.url.startsWith('/private-api/comment-history') ) { - return request + return request; } if (!request.data?.code) { @@ -47,12 +48,15 @@ api.interceptors.request.use((request) => { console.log('Added access token:', accessToken); } else { const isLoggedIn = state.application.isLoggedIn; - console.warn("Failed to inject accessToken", `isLoggedIn:${isLoggedIn}`) - bugsnagInstance.notify(new Error(`Failed to inject accessToken in ${request.url} call. isLoggedIn:${isLoggedIn}, local.acccessToken:${token}, pin:${pin}`)) + console.warn('Failed to inject accessToken', `isLoggedIn:${isLoggedIn}`); + bugsnagInstance.notify( + new Error( + `Failed to inject accessToken in ${request.url} call. isLoggedIn:${isLoggedIn}, local.acccessToken:${token}, pin:${pin}`, + ), + ); } } - return request; }); diff --git a/src/constants/defaultCoins.ts b/src/constants/defaultCoins.ts index f23972659..2cdb1b257 100644 --- a/src/constants/defaultCoins.ts +++ b/src/constants/defaultCoins.ts @@ -1,29 +1,33 @@ -import { CoinBase } from "../redux/reducers/walletReducer" +import { CoinBase } from '../redux/reducers/walletReducer'; -const DEFAULT_COINS = [{ - id:'ecency', - symbol:'Points', - notCrypto:true -},{ - id:'hive_power', - symbol:'HP', - notCrypto:true -},{ - id:'hive', - symbol:'HIVE', - notCrypto:false -},{ - id:'hive_dollar', - symbol:'HBD', - notCrypto:false -}] as CoinBase[] +const DEFAULT_COINS = [ + { + id: 'ecency', + symbol: 'Points', + notCrypto: true, + }, + { + id: 'hive_power', + symbol: 'HP', + notCrypto: true, + }, + { + id: 'hive', + symbol: 'HIVE', + notCrypto: false, + }, + { + id: 'hive_dollar', + symbol: 'HBD', + notCrypto: false, + }, +] as CoinBase[]; export const COIN_IDS = { - ECENCY:'ecency', - HIVE:'hive', - HBD:'hive_dollar', - HP:'hive_power' -} + ECENCY: 'ecency', + HIVE: 'hive', + HBD: 'hive_dollar', + HP: 'hive_power', +}; - -export default DEFAULT_COINS \ No newline at end of file +export default DEFAULT_COINS; diff --git a/src/constants/options/theme.ts b/src/constants/options/theme.ts index 1cade55c0..c1cf9e39f 100644 --- a/src/constants/options/theme.ts +++ b/src/constants/options/theme.ts @@ -1,6 +1,5 @@ export default [ - {key:'settings.theme.system', value: null}, - {key:'settings.theme.light', value: false}, - {key:'settings.theme.dark', value: true} - ]; - \ No newline at end of file + { key: 'settings.theme.system', value: null }, + { key: 'settings.theme.light', value: false }, + { key: 'settings.theme.dark', value: true }, +]; diff --git a/src/constants/settingsTypes.ts b/src/constants/settingsTypes.ts index dd57759a0..185a330b4 100644 --- a/src/constants/settingsTypes.ts +++ b/src/constants/settingsTypes.ts @@ -4,5 +4,5 @@ const DELETE_ACCOUNT = 'delete_account'; export default { SHOW_HIDE_IMGS, - DELETE_ACCOUNT + DELETE_ACCOUNT, }; diff --git a/src/constants/transferTypes.ts b/src/constants/transferTypes.ts index 842e7191c..3bcd3e9f7 100644 --- a/src/constants/transferTypes.ts +++ b/src/constants/transferTypes.ts @@ -10,7 +10,7 @@ const DELEGATE = 'delegate'; const POWER_DOWN = 'power_down'; const ADDRESS_VIEW = 'address_view'; const DELEGATE_VESTING_SHARES = 'delegate_vesting_shares'; -const WITHDRAW_VESTING = 'withdraw_vesting' +const WITHDRAW_VESTING = 'withdraw_vesting'; export default { TRANSFER_TOKEN, @@ -25,5 +25,5 @@ export default { POWER_DOWN, ADDRESS_VIEW, DELEGATE_VESTING_SHARES, - WITHDRAW_VESTING + WITHDRAW_VESTING, }; diff --git a/src/containers/inAppPurchaseContainer.tsx b/src/containers/inAppPurchaseContainer.tsx index 089fb1fdb..a9b2a5d61 100644 --- a/src/containers/inAppPurchaseContainer.tsx +++ b/src/containers/inAppPurchaseContainer.tsx @@ -47,18 +47,15 @@ class InAppPurchaseContainer extends Component { RNIap.endConnection(); } - _initContainer = async () => { - const { - intl, - } = this.props; + const { intl } = this.props; try { await RNIap.initConnection(); if (Platform.OS === 'android') { - await RNIap.flushFailedPurchasesCachedAsPendingAndroid(); + await RNIap.flushFailedPurchasesCachedAsPendingAndroid(); } - await this._consumeAvailablePurchases() + await this._consumeAvailablePurchases(); this._getItems(); this._purchaseUpdatedListener(); await this._handleQrPurchase(); @@ -70,31 +67,28 @@ class InAppPurchaseContainer extends Component { intl.formatMessage({ id: 'alert.connection_issues', }), - err.message + err.message, ); } - - } + }; - - //this snippet consumes all previously bought purchases + //this snippet consumes all previously bought purchases //that are set to be consumed yet _consumeAvailablePurchases = async () => { - try{ + try { //get available purchase const purchases = await RNIap.getAvailablePurchases(); //check consumeable status for (let i = 0; i < purchases.length; i++) { - //consume item using finishTransactionx + //consume item using finishTransactionx await RNIap.finishTransaction(purchases[i], true); } - }catch(err){ + } catch (err) { bugsnagInstance.notify(err); console.warn(err.code, err.message); } - } + }; - // Component Functions _purchaseUpdatedListener = () => { @@ -157,7 +151,7 @@ class InAppPurchaseContainer extends Component { intl.formatMessage({ id: 'alert.warning', }), - error.message + error.message, ); } this.setState({ isProcessing: false }); @@ -169,7 +163,7 @@ class InAppPurchaseContainer extends Component { if (_title !== 'FREE POINTS') { _title = _title.replace(/[^0-9]+/g, '') + ' POINTS'; } - + return _title; }; @@ -183,11 +177,11 @@ class InAppPurchaseContainer extends Component { } catch (err) { bugsnagInstance.notify(err); Alert.alert( - intl.formatMessage({ - id: 'alert.connection_issues', - }), - error.message - ); + intl.formatMessage({ + id: 'alert.connection_issues', + }), + error.message, + ); } this.setState({ isLoading: false }); @@ -219,23 +213,29 @@ class InAppPurchaseContainer extends Component { const productId = navigation.getParam('productId', ''); const username = navigation.getParam('username', ''); - const product:Product = productId && products && products.find((product) => product.productId === productId) - + const product: Product = + productId && products && products.find((product) => product.productId === productId); + if (product) { - - let body = intl.formatMessage({ - id: 'boost.confirm_purchase_summary' - }, { + let body = intl.formatMessage( + { + id: 'boost.confirm_purchase_summary', + }, + { points: this._getTitle(product.title), - username, - price: `${product.currency} ${product.price}` - }); + username, + price: `${product.currency} ${product.price}`, + }, + ); - let title = intl.formatMessage({ - id: 'boost.confirm_purchase' - }, { - username, - }); + let title = intl.formatMessage( + { + id: 'boost.confirm_purchase', + }, + { + username, + }, + ); dispatch( showActionModal({ @@ -251,13 +251,12 @@ class InAppPurchaseContainer extends Component { onPress: async () => await this._buyItem(productId), }, ], - headerContent: , + headerContent: , }), ); } - } + }; - render() { const { children, isNoSpin, navigation } = this.props; const { productList, isLoading, isProcessing } = this.state; @@ -276,7 +275,7 @@ class InAppPurchaseContainer extends Component { getItems: this._getItems, getTitle: this._getTitle, spinProduct: productList.filter((item) => item.productId.includes('spins')), - navigation: navigation + navigation: navigation, }) ); } diff --git a/src/navigation/appNavigator.tsx b/src/navigation/appNavigator.tsx index 1b4f166d5..0b06ccbc5 100644 --- a/src/navigation/appNavigator.tsx +++ b/src/navigation/appNavigator.tsx @@ -10,22 +10,19 @@ import { setTopLevelNavigator } from './service'; import ROUTES from '../constants/routeNames'; import parseVersionNumber from '../utils/parseVersionNumber'; - - export const AppNavigator = () => { - - const lastAppVersion = useAppSelector(state => state.application.lastAppVersion) + const lastAppVersion = useAppSelector((state) => state.application.lastAppVersion); const [appVersion] = useState(VersionNumber.appVersion); - const _initRoute = (!lastAppVersion || (parseVersionNumber(lastAppVersion) < parseVersionNumber(appVersion))) ? - ROUTES.SCREENS.WELCOME : ROUTES.SCREENS.FEED; - + const _initRoute = + !lastAppVersion || parseVersionNumber(lastAppVersion) < parseVersionNumber(appVersion) + ? ROUTES.SCREENS.WELCOME + : ROUTES.SCREENS.FEED; return ( - setTopLevelNavigator(ref)}> + setTopLevelNavigator(ref)}> - ) -} - + ); +}; diff --git a/src/navigation/botomTabNavigator.tsx b/src/navigation/botomTabNavigator.tsx index e7e1192b8..7a4c7fbdd 100644 --- a/src/navigation/botomTabNavigator.tsx +++ b/src/navigation/botomTabNavigator.tsx @@ -1,75 +1,65 @@ - import React from 'react'; import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'; - import ROUTES from '../constants/routeNames'; import { BottomTabBar } from '../components'; -import { - Feed, - Notification, - Profile, - Wallet, -} from '../screens'; +import { Feed, Notification, Profile, Wallet } from '../screens'; const Tab = createBottomTabNavigator(); export const BottomTabNavigator = () => { + return ( + } + backBehavior="initialRoute" + screenOptions={{ + headerShown: false, + tabBarShowLabel: false, + tabBarActiveTintColor: '#357ce6', + tabBarInactiveTintColor: '#c1c5c7', + }} + > + + - return ( - } + - backBehavior='initialRoute' - screenOptions={{ - headerShown:false, - tabBarShowLabel: false, - tabBarActiveTintColor: '#357ce6', - tabBarInactiveTintColor: '#c1c5c7',}} - > - + - + + + ); +}; - - - - - - - ) -} - - -const EmptyScreen = () => null \ No newline at end of file +const EmptyScreen = () => null; diff --git a/src/navigation/drawerNavigator.tsx b/src/navigation/drawerNavigator.tsx index f827b337c..20efcd916 100644 --- a/src/navigation/drawerNavigator.tsx +++ b/src/navigation/drawerNavigator.tsx @@ -1,19 +1,20 @@ import React from 'react'; -import { SideMenu } from "../components" -import { BottomTabNavigator } from "./botomTabNavigator" +import { createDrawerNavigator } from '@react-navigation/drawer'; +import { SideMenu } from '../components'; +import { BottomTabNavigator } from './botomTabNavigator'; // Constants import ROUTES from '../constants/routeNames'; -import { createDrawerNavigator } from "@react-navigation/drawer"; - const Drawer = createDrawerNavigator(); export const DrawerNavigator = () => { - - return ( - } > - - - ) -} \ No newline at end of file + return ( + } + > + + + ); +}; diff --git a/src/navigation/index.ts b/src/navigation/index.ts index 217418cdb..a914f6a92 100644 --- a/src/navigation/index.ts +++ b/src/navigation/index.ts @@ -1 +1 @@ -export * from './appNavigator'; \ No newline at end of file +export * from './appNavigator'; diff --git a/src/navigation/stackNavigator.tsx b/src/navigation/stackNavigator.tsx index 2e47776e1..56f4338d9 100644 --- a/src/navigation/stackNavigator.tsx +++ b/src/navigation/stackNavigator.tsx @@ -1,94 +1,95 @@ import React from 'react'; // Constants +import { createNativeStackNavigator } from '@react-navigation/native-stack'; import ROUTES from '../constants/routeNames'; -import { createNativeStackNavigator } from '@react-navigation/native-stack'; // Screens import { - Bookmarks, - Boost, - Drafts, - Editor, - Follows, - Login, - Post, - Profile, - ProfileEdit, - Reblogs, - Redeem, - Register, - SearchResult, - Settings, - SpinGame, - Transfer, - Voters, - AccountBoost, - TagResult, - Community, - Communities, - WebBrowser, - ReferScreen, - CoinDetails, - EditHistoryScreen, - WelcomeScreen, - PinCode, + Bookmarks, + Boost, + Drafts, + Editor, + Follows, + Login, + Post, + Profile, + ProfileEdit, + Reblogs, + Redeem, + Register, + SearchResult, + Settings, + SpinGame, + Transfer, + Voters, + AccountBoost, + TagResult, + Community, + Communities, + WebBrowser, + ReferScreen, + CoinDetails, + EditHistoryScreen, + WelcomeScreen, + PinCode, } from '../screens'; import { DrawerNavigator } from './drawerNavigator'; - const RootStack = createNativeStackNavigator(); const MainStack = createNativeStackNavigator(); const MainStackNavigator = () => { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ) -} + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; -export const StackNavigator = ({initRoute}) => { +export const StackNavigator = ({ initRoute }) => { + return ( + - initialRouteName={initRoute} - screenOptions={{ headerShown: false, animation:'slide_from_bottom' }}> - - - - - - - - - ) -} + + + + + + ); +}; diff --git a/src/providers/coingecko/coingecko.ts b/src/providers/coingecko/coingecko.ts index 11ebe0012..fb96097ad 100644 --- a/src/providers/coingecko/coingecko.ts +++ b/src/providers/coingecko/coingecko.ts @@ -3,7 +3,6 @@ import coingeckoApi from '../../config/coingeckoApi'; import { convertMarketData } from './converters'; import { MarketData } from './models'; - const PATH_COINS = 'coins'; const PATH_MARKET_CHART = 'market_chart'; @@ -11,32 +10,31 @@ export const INTERVAL_HOURLY = 'hourly'; export const INTERVAL_DAILY = 'daily'; export const fetchMarketChart = async ( - coingeckoId:string, - vs_currency:string, - days:number, - interval:'daily'|'hourly' = 'daily' - ): Promise => { - try{ - const params = { - vs_currency, - days, - interval - } + coingeckoId: string, + vs_currency: string, + days: number, + interval: 'daily' | 'hourly' = 'daily', +): Promise => { + try { + const params = { + vs_currency, + days, + interval, + }; - const res = await coingeckoApi.get(`/${PATH_COINS}/${coingeckoId}/${PATH_MARKET_CHART}`, { - params - }); - const rawData = res.data; - if(!rawData){ - throw new Error("Tag name not available") - } + const res = await coingeckoApi.get(`/${PATH_COINS}/${coingeckoId}/${PATH_MARKET_CHART}`, { + params, + }); + const rawData = res.data; + if (!rawData) { + throw new Error('Tag name not available'); + } - const data = convertMarketData(rawData); + const data = convertMarketData(rawData); - return data; - - }catch(error){ - bugsnagInstance.notify(error); - throw error; - } -} + return data; + } catch (error) { + bugsnagInstance.notify(error); + throw error; + } +}; diff --git a/src/providers/coingecko/converters.ts b/src/providers/coingecko/converters.ts index 3fe8bffaa..f8ab47360 100644 --- a/src/providers/coingecko/converters.ts +++ b/src/providers/coingecko/converters.ts @@ -1,23 +1,23 @@ -import { ChartItem, MarketData } from "./models" +import { ChartItem, MarketData } from './models'; -export const convertChartItem = (rawData:any) => { - if(!rawData){ - return null; - } - return { - xValue:rawData[0], - yValue:rawData[1] - } as ChartItem; -} +export const convertChartItem = (rawData: any) => { + if (!rawData) { + return null; + } + return { + xValue: rawData[0], + yValue: rawData[1], + } as ChartItem; +}; -export const convertMarketData = (rawData:any) => { - if(!rawData){ - return null; - } +export const convertMarketData = (rawData: any) => { + if (!rawData) { + return null; + } - return { - prices:rawData.prices ? rawData.prices.map(convertChartItem) : [], - marketCaps:rawData.market_caps ? rawData.market_caps.map(convertChartItem) : [], - totalVolumes:rawData.total_volumes ? rawData.total_volumes.map(convertChartItem) : [] - } as MarketData; -} \ No newline at end of file + return { + prices: rawData.prices ? rawData.prices.map(convertChartItem) : [], + marketCaps: rawData.market_caps ? rawData.market_caps.map(convertChartItem) : [], + totalVolumes: rawData.total_volumes ? rawData.total_volumes.map(convertChartItem) : [], + } as MarketData; +}; diff --git a/src/providers/coingecko/models.ts b/src/providers/coingecko/models.ts index 8df68d502..c17dd292c 100644 --- a/src/providers/coingecko/models.ts +++ b/src/providers/coingecko/models.ts @@ -1,10 +1,10 @@ export interface ChartItem { - xValue:number, - yValue:number + xValue: number; + yValue: number; } export interface MarketData { - prices:Array; - marketCaps:Array; - totalVolumes:Array; -} \ No newline at end of file + prices: Array; + marketCaps: Array; + totalVolumes: Array; +} diff --git a/src/providers/ecency/converters.ts b/src/providers/ecency/converters.ts index 2114bb8e4..efc58a5e3 100644 --- a/src/providers/ecency/converters.ts +++ b/src/providers/ecency/converters.ts @@ -1,6 +1,12 @@ import { COIN_IDS } from '../../constants/defaultCoins'; import { Referral } from '../../models'; -import { CommentHistoryItem, LatestMarketPrices, LatestQuotes, QuoteItem, ReferralStat } from './ecency.types'; +import { + CommentHistoryItem, + LatestMarketPrices, + LatestQuotes, + QuoteItem, + ReferralStat, +} from './ecency.types'; export const convertReferral = (rawData: any) => { return { @@ -19,23 +25,23 @@ export const convertReferralStat = (rawData: any) => { } as ReferralStat; }; -export const convertQuoteItem = (rawData:any, currencyRate:number) => { - if(!rawData){ +export const convertQuoteItem = (rawData: any, currencyRate: number) => { + if (!rawData) { return null; } return { - price:rawData.price * currencyRate, - percentChange:rawData.percent_change, - lastUpdated:rawData.last_updated, - } as QuoteItem -} + price: rawData.price * currencyRate, + percentChange: rawData.percent_change, + lastUpdated: rawData.last_updated, + } as QuoteItem; +}; -export const convertLatestQuotes = (rawData: any, currencyRate:number) => { +export const convertLatestQuotes = (rawData: any, currencyRate: number) => { return { - [COIN_IDS.HIVE]:convertQuoteItem(rawData.hive.quotes.usd, currencyRate), - [COIN_IDS.HP]:convertQuoteItem(rawData.hive.quotes.usd, currencyRate), - [COIN_IDS.HBD]:convertQuoteItem(rawData.hbd.quotes.usd, currencyRate), - [COIN_IDS.ECENCY]:convertQuoteItem(rawData.estm.quotes.usd, currencyRate) + [COIN_IDS.HIVE]: convertQuoteItem(rawData.hive.quotes.usd, currencyRate), + [COIN_IDS.HP]: convertQuoteItem(rawData.hive.quotes.usd, currencyRate), + [COIN_IDS.HBD]: convertQuoteItem(rawData.hbd.quotes.usd, currencyRate), + [COIN_IDS.ECENCY]: convertQuoteItem(rawData.estm.quotes.usd, currencyRate), } as LatestQuotes; }; @@ -47,4 +53,4 @@ export const convertCommentHistory = (rawData: any) => { title: rawData.title || '', v: rawData.v || 1, } as CommentHistoryItem; -}; \ No newline at end of file +}; diff --git a/src/providers/ecency/ePoint.ts b/src/providers/ecency/ePoint.ts index 019d1c4d4..4ac9cda6a 100644 --- a/src/providers/ecency/ePoint.ts +++ b/src/providers/ecency/ePoint.ts @@ -4,18 +4,16 @@ import ecencyApi from '../../config/ecencyApi'; import bugsnagInstance from '../../config/bugsnag'; import { EcencyUser, UserPoint } from './ecency.types'; - /** * Records user activty and reward poinsts * @param ty points * @param bl block number * @param tx transaction id - * @returns + * @returns */ export const userActivity = async (ty: number, tx: string = '', bl: string | number = '') => { try { const data: { - ty: number; bl?: string | number; tx?: string | number; @@ -24,28 +22,27 @@ export const userActivity = async (ty: number, tx: string = '', bl: string | num if (bl) data.bl = bl; if (tx) data.tx = tx; - const response = await ecencyApi.post('/private-api/usr-activity', data) + const response = await ecencyApi.post('/private-api/usr-activity', data); return response.data; } catch (error) { - console.warn("Failed to push user activity point", error); - bugsnagInstance.notify(error) - throw error - } -} - - -export const getPointsSummary = async (username:string): Promise => { - try { - const data = {username}; - const response = await ecencyApi.post('/private-api/points', data); - console.log("returning user points data", response.data); - return response.data; - } catch (error) { - console.warn("Failed to get points", error); + console.warn('Failed to push user activity point', error); bugsnagInstance.notify(error); - throw new Error(error.response?.data?.message || error.message) + throw error; } -} +}; + +export const getPointsSummary = async (username: string): Promise => { + try { + const data = { username }; + const response = await ecencyApi.post('/private-api/points', data); + console.log('returning user points data', response.data); + return response.data; + } catch (error) { + console.warn('Failed to get points', error); + bugsnagInstance.notify(error); + throw new Error(error.response?.data?.message || error.message); + } +}; export const getPointsHistory = (username: string): Promise => new Promise((resolve) => { @@ -60,18 +57,16 @@ export const getPointsHistory = (username: string): Promise => }); }); - export const claimPoints = async () => { try { - const response = await ecencyApi.post('/private-api/points-claim') + const response = await ecencyApi.post('/private-api/points-claim'); return response.data; } catch (error) { - console.warn("Failed to calim points", error); + console.warn('Failed to calim points', error); bugsnagInstance.notify(error); - throw new Error(error.response?.data?.message || error.message) + throw new Error(error.response?.data?.message || error.message); } -} - +}; export const gameStatusCheck = (username, type) => new Promise((resolve, reject) => { diff --git a/src/providers/ecency/ecency.types.ts b/src/providers/ecency/ecency.types.ts index 6158383d6..8d12d1811 100644 --- a/src/providers/ecency/ecency.types.ts +++ b/src/providers/ecency/ecency.types.ts @@ -66,10 +66,10 @@ export interface CommentHistoryItem { } export interface PointActivity { - pointsTy:number; - username?:string; - transactionId?:string; - blockNum?:number|string; + pointsTy: number; + username?: string; + transactionId?: string; + blockNum?: number | string; } export enum ScheduledPostStatus { @@ -80,18 +80,17 @@ export enum ScheduledPostStatus { } export enum NotificationFilters { - ACTIVITIES = "activities", - RVOTES = "rvotes", - MENTIONS = "mentions", - FOLLOWS = "follows", - REPLIES = "replies", - REBLOGS = "reblogs", - TRANFERS = "transfers", - DELEGATIONS = "delegations", - FAVOURITES = "nfavorites" + ACTIVITIES = 'activities', + RVOTES = 'rvotes', + MENTIONS = 'mentions', + FOLLOWS = 'follows', + REPLIES = 'replies', + REBLOGS = 'reblogs', + TRANFERS = 'transfers', + DELEGATIONS = 'delegations', + FAVOURITES = 'nfavorites', } - export enum PointActivityIds { VIEW_POST = 10, LOGIN = 20, diff --git a/src/providers/hive/hive.types.ts b/src/providers/hive/hive.types.ts index bb14141b0..ebb737323 100644 --- a/src/providers/hive/hive.types.ts +++ b/src/providers/hive/hive.types.ts @@ -1,113 +1,111 @@ - export interface Vote { - percent: number; - reputation: number; - rshares: string; - time: string; - timestamp?: number; - voter: string; - weight: number; - reward?: number; + percent: number; + reputation: number; + rshares: string; + time: string; + timestamp?: number; + voter: string; + weight: number; + reward?: number; } export interface DynamicGlobalProperties { - hbd_print_rate: number; - total_vesting_fund_hive: string; - total_vesting_shares: string; - hbd_interest_rate: number; - head_block_number: number; - vesting_reward_percent: number; - virtual_supply: string; + hbd_print_rate: number; + total_vesting_fund_hive: string; + total_vesting_shares: string; + hbd_interest_rate: number; + head_block_number: number; + vesting_reward_percent: number; + virtual_supply: string; } export interface FeedHistory { - current_median_history: { - base: string; - quote: string; - }; + current_median_history: { + base: string; + quote: string; + }; } export interface RewardFund { - recent_claims: string; - reward_balance: string; + recent_claims: string; + reward_balance: string; } export interface DelegatedVestingShare { - id: number; - delegatee: string; - delegator: string; - min_delegation_time: string; - vesting_shares: string; + id: number; + delegatee: string; + delegator: string; + min_delegation_time: string; + vesting_shares: string; } export interface Follow { - follower: string; - following: string; - what: string[]; + follower: string; + following: string; + what: string[]; } export interface MarketStatistics { - hbd_volume: string; - highest_bid: string; - hive_volume: string; - latest: string; - lowest_ask: string; - percent_change: string; + hbd_volume: string; + highest_bid: string; + hive_volume: string; + latest: string; + lowest_ask: string; + percent_change: string; } export interface OpenOrderItem { - id: number, - created: string, - expiration: string, - seller: string, - orderid: number, - for_sale: number, - sell_price: { - base: string, - quote: string - }, - real_price: string, - rewarded: boolean + id: number; + created: string; + expiration: string; + seller: string; + orderid: number; + for_sale: number; + sell_price: { + base: string; + quote: string; + }; + real_price: string; + rewarded: boolean; } - export interface OrdersDataItem { - created: string; - hbd: number; - hive: number; - order_price: { - base: string; - quote: string; - } - real_price: string; + created: string; + hbd: number; + hive: number; + order_price: { + base: string; + quote: string; + }; + real_price: string; } export interface TradeDataItem { - current_pays: string; - date: number; - open_pays: string; + current_pays: string; + date: number; + open_pays: string; } export interface OrdersData { - bids: OrdersDataItem[]; - asks: OrdersDataItem[]; - trading: OrdersDataItem[]; + bids: OrdersDataItem[]; + asks: OrdersDataItem[]; + trading: OrdersDataItem[]; } export interface ConversionRequest { - amount: string; - conversion_date: string; - id: number; - owner: string; - requestid: number; + amount: string; + conversion_date: string; + id: number; + owner: string; + requestid: number; } export interface SavingsWithdrawRequest { - id: number; - from: string; - to: string; - memo: string; - request_id: number; - amount: string; - complete: string; -} \ No newline at end of file + id: number; + from: string; + to: string; + memo: string; + request_id: number; + amount: string; + complete: string; +} diff --git a/src/providers/queries/editorQueries.ts b/src/providers/queries/editorQueries.ts index fca42f030..04506ba95 100644 --- a/src/providers/queries/editorQueries.ts +++ b/src/providers/queries/editorQueries.ts @@ -4,209 +4,201 @@ import { Image } from 'react-native-image-crop-picker'; import { useAppDispatch, useAppSelector } from '../../hooks'; import { toastNotification } from '../../redux/actions/uiAction'; import { - addFragment, - addImage, - deleteFragment, - deleteImage, - getFragments, - getImages, - updateFragment, - uploadImage, + addFragment, + addImage, + deleteFragment, + deleteImage, + getFragments, + getImages, + updateFragment, + uploadImage, } from '../ecency/ecency'; import { MediaItem, Snippet } from '../ecency/ecency.types'; import { signImage } from '../hive/dhive'; import QUERIES from './queryKeys'; interface SnippetMutationVars { - id: string | null; - title: string; - body: string; + id: string | null; + title: string; + body: string; } interface MediaUploadVars { - media: Image; - addToUploads: boolean; + media: Image; + addToUploads: boolean; } - - /** GET QUERIES **/ export const useMediaQuery = () => { - const intl = useIntl(); - const dispatch = useAppDispatch(); - return useQuery([QUERIES.MEDIA.GET], getImages, { - initialData: [], - onError: () => { - dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); - }, - }); + const intl = useIntl(); + const dispatch = useAppDispatch(); + return useQuery([QUERIES.MEDIA.GET], getImages, { + initialData: [], + onError: () => { + dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); + }, + }); }; export const useSnippetsQuery = () => { - const intl = useIntl(); - const dispatch = useAppDispatch(); - return useQuery([QUERIES.SNIPPETS.GET], getFragments, { - initialData: [], - onError: () => { - dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); - }, - }); + const intl = useIntl(); + const dispatch = useAppDispatch(); + return useQuery([QUERIES.SNIPPETS.GET], getFragments, { + initialData: [], + onError: () => { + dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); + }, + }); }; - - - /** ADD UPDATE MUTATIONS **/ - export const useAddToUploadsMutation = () => { - const intl = useIntl(); - const dispatch = useAppDispatch(); - const queryClient = useQueryClient(); + const intl = useIntl(); + const dispatch = useAppDispatch(); + const queryClient = useQueryClient(); - return useMutation(addImage, { - retry: 3, - onSuccess: (data) => { - queryClient.setQueryData([QUERIES.MEDIA.GET], data); - }, - onError: (error) => { - if (error.toString().includes('code 409')) { - //means image ware already preset, refresh to get updated order - queryClient.invalidateQueries([QUERIES.MEDIA.GET]); - } else { - dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); - } - - } - }) -} - - -export const useMediaUploadMutation = () => { - const intl = useIntl(); - const dispatch = useAppDispatch(); - - const addToUploadsMutation = useAddToUploadsMutation(); - - const currentAccount = useAppSelector(state => state.account.currentAccount); - const pinCode = useAppSelector(state => state.application.pin); - - return useMutation( - async ({ media }) => { - console.log('uploading media', media); - let sign = await signImage(media, currentAccount, pinCode); - return await uploadImage(media, currentAccount.name, sign); - }, - { - retry: 3, - onSuccess: (response, { addToUploads }) => { - if (addToUploads && response && response.url) { - console.log('adding image to gallery', response.url); - addToUploadsMutation.mutate(response.url); - } - }, - onError: () => { - dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); - }, - }, - ); -} - -export const useSnippetsMutation = () => { - const intl = useIntl(); - const dispatch = useAppDispatch(); - const queryClient = useQueryClient(); - - return useMutation( - async (vars) => { - console.log('going to add/update snippet', vars); - if (vars.id) { - const response = await updateFragment(vars.id, vars.title, vars.body); - return response; - } else { - const response = await addFragment(vars.title, vars.body); - return response; - } - }, - { - onMutate: (vars) => { - console.log('mutate snippets for add/update', vars); - - const _newItem = { - id: vars.id, - title: vars.title, - body: vars.body, - created: new Date().toDateString(), - modified: new Date().toDateString(), - } as Snippet; - - const data = queryClient.getQueryData([QUERIES.SNIPPETS.GET]); - - let _newData: Snippet[] = data ? [...data] : []; - if (vars.id) { - const snipIndex = _newData.findIndex((item) => vars.id === item.id); - _newData[snipIndex] = _newItem; - } else { - _newData = [_newItem, ..._newData]; - } - - queryClient.setQueryData([QUERIES.SNIPPETS.GET], _newData); - }, - onSuccess: (data) => { - console.log('added/updated snippet', data); - queryClient.invalidateQueries([QUERIES.SNIPPETS.GET]); - }, - onError: () => { - dispatch(toastNotification(intl.formatMessage({ id: 'snippets.message_failed' }))); - }, - }, - ); + return useMutation(addImage, { + retry: 3, + onSuccess: (data) => { + queryClient.setQueryData([QUERIES.MEDIA.GET], data); + }, + onError: (error) => { + if (error.toString().includes('code 409')) { + //means image ware already preset, refresh to get updated order + queryClient.invalidateQueries([QUERIES.MEDIA.GET]); + } else { + dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); + } + }, + }); }; +export const useMediaUploadMutation = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + const addToUploadsMutation = useAddToUploadsMutation(); + + const currentAccount = useAppSelector((state) => state.account.currentAccount); + const pinCode = useAppSelector((state) => state.application.pin); + + return useMutation( + async ({ media }) => { + console.log('uploading media', media); + let sign = await signImage(media, currentAccount, pinCode); + return await uploadImage(media, currentAccount.name, sign); + }, + { + retry: 3, + onSuccess: (response, { addToUploads }) => { + if (addToUploads && response && response.url) { + console.log('adding image to gallery', response.url); + addToUploadsMutation.mutate(response.url); + } + }, + onError: () => { + dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); + }, + }, + ); +}; + +export const useSnippetsMutation = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + const queryClient = useQueryClient(); + + return useMutation( + async (vars) => { + console.log('going to add/update snippet', vars); + if (vars.id) { + const response = await updateFragment(vars.id, vars.title, vars.body); + return response; + } else { + const response = await addFragment(vars.title, vars.body); + return response; + } + }, + { + onMutate: (vars) => { + console.log('mutate snippets for add/update', vars); + + const _newItem = { + id: vars.id, + title: vars.title, + body: vars.body, + created: new Date().toDateString(), + modified: new Date().toDateString(), + } as Snippet; + + const data = queryClient.getQueryData([QUERIES.SNIPPETS.GET]); + + let _newData: Snippet[] = data ? [...data] : []; + if (vars.id) { + const snipIndex = _newData.findIndex((item) => vars.id === item.id); + _newData[snipIndex] = _newItem; + } else { + _newData = [_newItem, ..._newData]; + } + + queryClient.setQueryData([QUERIES.SNIPPETS.GET], _newData); + }, + onSuccess: (data) => { + console.log('added/updated snippet', data); + queryClient.invalidateQueries([QUERIES.SNIPPETS.GET]); + }, + onError: () => { + dispatch(toastNotification(intl.formatMessage({ id: 'snippets.message_failed' }))); + }, + }, + ); +}; /** DELETE MUTATIONS **/ export const useMediaDeleteMutation = () => { - const queryClient = useQueryClient(); - const dispatch = useAppDispatch(); - const intl = useIntl(); - return useMutation(async (deleteIds) => { - for (const i in deleteIds) { - await deleteImage(deleteIds[i]); + const queryClient = useQueryClient(); + const dispatch = useAppDispatch(); + const intl = useIntl(); + return useMutation( + async (deleteIds) => { + for (const i in deleteIds) { + await deleteImage(deleteIds[i]); + } + return deleteIds; + }, + { + retry: 3, + onSuccess: (deleteIds) => { + console.log('Success media deletion delete', deleteIds); + const data: MediaItem[] | undefined = queryClient.getQueryData([QUERIES.MEDIA.GET]); + if (data) { + const _newData = data.filter((item) => !deleteIds.includes(item._id)); + queryClient.setQueryData([QUERIES.MEDIA.GET], _newData); } - return deleteIds; - }, { - retry: 3, - onSuccess: (deleteIds) => { - console.log('Success media deletion delete', deleteIds); - const data: MediaItem[] | undefined = queryClient.getQueryData([QUERIES.MEDIA.GET]); - if (data) { - const _newData = data.filter((item) => (!deleteIds.includes(item._id))) - queryClient.setQueryData([QUERIES.MEDIA.GET], _newData); - } - }, - onError: () => { - dispatch(toastNotification(intl.formatMessage({ id: 'uploads_modal.delete_failed' }))); - queryClient.invalidateQueries([QUERIES.MEDIA.GET]); - }, - }); + }, + onError: () => { + dispatch(toastNotification(intl.formatMessage({ id: 'uploads_modal.delete_failed' }))); + queryClient.invalidateQueries([QUERIES.MEDIA.GET]); + }, + }, + ); }; - export const useSnippetDeleteMutation = () => { - const queryClient = useQueryClient(); - const dispatch = useAppDispatch(); - const intl = useIntl(); - return useMutation(deleteFragment, { - retry: 3, - onSuccess: (data) => { - console.log('Success scheduled post delete', data); - queryClient.setQueryData([QUERIES.SNIPPETS.GET], data); - }, - onError: () => { - dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); - }, - }); + const queryClient = useQueryClient(); + const dispatch = useAppDispatch(); + const intl = useIntl(); + return useMutation(deleteFragment, { + retry: 3, + onSuccess: (data) => { + console.log('Success scheduled post delete', data); + queryClient.setQueryData([QUERIES.SNIPPETS.GET], data); + }, + onError: () => { + dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' }))); + }, + }); }; diff --git a/src/providers/queries/index.ts b/src/providers/queries/index.ts index 52ecfbdeb..4efba048a 100644 --- a/src/providers/queries/index.ts +++ b/src/providers/queries/index.ts @@ -26,4 +26,4 @@ export const initQueryClient = () => { export * from './notificationQueries'; export * from './draftQueries'; export * from './editorQueries'; -export * from './pointQueries' +export * from './pointQueries'; diff --git a/src/providers/queries/pointQueries.ts b/src/providers/queries/pointQueries.ts index 9b61ac386..45cba6caa 100644 --- a/src/providers/queries/pointQueries.ts +++ b/src/providers/queries/pointQueries.ts @@ -1,77 +1,72 @@ -import { useMutation } from "@tanstack/react-query" +import { useMutation } from '@tanstack/react-query'; import { useAppSelector, useAppDispatch } from '../../hooks'; -import { deletePointActivityCache, updatePointActivityCache } from "../../redux/actions/cacheActions"; -import { generateRndStr } from "../../utils/editor"; -import { PointActivity, PointActivityIds } from "../ecency/ecency.types"; -import { userActivity } from "../ecency/ePoint" - - +import { + deletePointActivityCache, + updatePointActivityCache, +} from '../../redux/actions/cacheActions'; +import { generateRndStr } from '../../utils/editor'; +import { PointActivity, PointActivityIds } from '../ecency/ecency.types'; +import { userActivity } from '../ecency/ePoint'; interface UserActivityMutationVars { - pointsTy: PointActivityIds; - blockNum?: string|number; - transactionId?: string; - cacheId?: string + pointsTy: PointActivityIds; + blockNum?: string | number; + transactionId?: string; + cacheId?: string; } - export const useUserActivityMutation = () => { - const dispatch = useAppDispatch(); - const currentAccount = useAppSelector(state => state.account.currentAccount); - const pointActivitiesCache:Map = useAppSelector(state => state.cache.pointActivities); + const dispatch = useAppDispatch(); + const currentAccount = useAppSelector((state) => state.account.currentAccount); + const pointActivitiesCache: Map = useAppSelector( + (state) => state.cache.pointActivities, + ); + const _mutationFn = async ({ pointsTy, blockNum, transactionId }: UserActivityMutationVars) => { + await userActivity(pointsTy, transactionId, blockNum); + return true; + }; - const _mutationFn = async ({ pointsTy, blockNum, transactionId }: UserActivityMutationVars) => { - - await userActivity(pointsTy, transactionId, blockNum) - return true; - } + const mutation = useMutation(_mutationFn, { + retry: 2, + onSuccess: (data, vars) => { + console.log('successfully logged activity', data, vars); + //remove entry from redux + if (vars.cacheId) { + console.log('must remove from redux'); + dispatch(deletePointActivityCache(vars.cacheId)); + } + }, + onError: (error, vars) => { + console.log('failed to log activity', error, vars); + //add entry in redux + if (!vars.cacheId && currentAccount) { + console.log('must add to from redux'); + const cacheId = generateRndStr(); + const { username } = currentAccount; + dispatch(updatePointActivityCache(cacheId, { ...vars, username })); + } + }, + }); - const mutation = useMutation(_mutationFn, { - retry: 2, - onSuccess: (data, vars) => { - console.log("successfully logged activity", data, vars) - //remove entry from redux - if (vars.cacheId) { - console.log("must remove from redux") - dispatch(deletePointActivityCache(vars.cacheId)) - } - }, - onError: (error, vars) => { - console.log("failed to log activity", error, vars) - //add entry in redux - if (!vars.cacheId && currentAccount) { - console.log("must add to from redux") - const cacheId = generateRndStr(); - const { username } = currentAccount; - dispatch(updatePointActivityCache(cacheId, { ...vars, username })) - } - } - }) + const lazyMutatePendingActivities = () => { + setTimeout(() => { + //read pending activities from redux + if (currentAccount && pointActivitiesCache && pointActivitiesCache.size) { + Array.from(pointActivitiesCache).forEach(([id, activity]) => { + if (currentAccount.username === activity.username) { + mutation.mutate({ + cacheId: id, + ...activity, + }); + } + }); + } + }, 3000); + }; - - const lazyMutatePendingActivities = () => { - setTimeout(()=>{ - //read pending activities from redux - if (currentAccount && pointActivitiesCache && pointActivitiesCache.size) { - - Array.from(pointActivitiesCache).forEach(([id, activity]) => { - if (currentAccount.username === activity.username) { - mutation.mutate({ - cacheId: id, - ...activity, - }) - } - - }) - } - }, 3000) - - } - - - return { - ...mutation, - lazyMutatePendingActivities, - } -} \ No newline at end of file + return { + ...mutation, + lazyMutatePendingActivities, + }; +}; diff --git a/src/redux/actions/cacheActions.ts b/src/redux/actions/cacheActions.ts index 28df36e7f..c8926226a 100644 --- a/src/redux/actions/cacheActions.ts +++ b/src/redux/actions/cacheActions.ts @@ -13,87 +13,99 @@ import { DELETE_SUBSCRIBED_COMMUNITY_CACHE, CLEAR_SUBSCRIBED_COMMUNITIES_CACHE, DELETE_POINT_ACTIVITY_CACHE_ENTRY, - UPDATE_POINT_ACTIVITY_CACHE + UPDATE_POINT_ACTIVITY_CACHE, } from '../constants/constants'; -import { Comment, CommentCacheStatus, Draft, SubscribedCommunity, Vote } from '../reducers/cacheReducer'; - - +import { + Comment, + CommentCacheStatus, + Draft, + SubscribedCommunity, + Vote, +} from '../reducers/cacheReducer'; export const updateVoteCache = (postPath: string, vote: Vote) => ({ payload: { postPath, - vote + vote, }, - type: UPDATE_VOTE_CACHE -}) - + type: UPDATE_VOTE_CACHE, +}); interface CommentCacheOptions { isUpdate?: boolean; parentTags?: Array; } -export const updateCommentCache = (commentPath: string, comment: Comment, options: CommentCacheOptions = { isUpdate: false }) => { - - console.log("body received:", comment.markdownBody); +export const updateCommentCache = ( + commentPath: string, + comment: Comment, + options: CommentCacheOptions = { isUpdate: false }, +) => { + console.log('body received:', comment.markdownBody); const updated = new Date(); updated.setSeconds(updated.getSeconds() - 5); //make cache delayed by 5 seconds to avoid same updated stamp in post data const updatedStamp = updated.toISOString().substring(0, 19); //server only return 19 character time string without timezone part if (options.isUpdate && !comment.created) { - throw new Error("For comment update, created prop must be provided from original comment data to update local cache"); + throw new Error( + 'For comment update, created prop must be provided from original comment data to update local cache', + ); } if (!options.parentTags && !comment.json_metadata) { - throw new Error("either of json_metadata in comment data or parentTags in options must be provided"); + throw new Error( + 'either of json_metadata in comment data or parentTags in options must be provided', + ); } - - - comment.created = comment.created || updatedStamp; //created will be set only once for new comment; + comment.created = comment.created || updatedStamp; //created will be set only once for new comment; comment.updated = comment.updated || updatedStamp; - comment.expiresAt = comment.expiresAt || updated.getTime() + 6000000;//600000; + comment.expiresAt = comment.expiresAt || updated.getTime() + 6000000; //600000; comment.active_votes = comment.active_votes || []; comment.net_rshares = comment.net_rshares || 0; comment.author_reputation = comment.author_reputation || 25; comment.total_payout = comment.total_payout || 0; - comment.json_metadata = comment.json_metadata || makeJsonMetadataReply(options.parentTags) + comment.json_metadata = comment.json_metadata || makeJsonMetadataReply(options.parentTags); comment.isDeletable = comment.isDeletable || true; comment.status = comment.status || CommentCacheStatus.PENDING; - comment.body = renderPostBody({ - author: comment.author, - permlink: comment.permlink, - last_update: comment.updated, - body: comment.markdownBody, - }, true, Platform.OS === 'android'); + comment.body = renderPostBody( + { + author: comment.author, + permlink: comment.permlink, + last_update: comment.updated, + body: comment.markdownBody, + }, + true, + Platform.OS === 'android', + ); - return ({ + return { payload: { commentPath, - comment + comment, }, - type: UPDATE_COMMENT_CACHE - }) -} + type: UPDATE_COMMENT_CACHE, + }; +}; export const deleteCommentCacheEntry = (commentPath: string) => ({ payload: commentPath, - type: DELETE_COMMENT_CACHE_ENTRY -}) + type: DELETE_COMMENT_CACHE_ENTRY, +}); export const updateDraftCache = (id: string, draft: Draft) => ({ payload: { id, - draft + draft, }, - type: UPDATE_DRAFT_CACHE -}) + type: UPDATE_DRAFT_CACHE, +}); export const deleteDraftCacheEntry = (id: string) => ({ payload: id, - type: DELETE_DRAFT_CACHE_ENTRY -}) + type: DELETE_DRAFT_CACHE_ENTRY, +}); export const updateSubscribedCommunitiesCache = (data: any) => { const path = data.communityId; @@ -102,43 +114,42 @@ export const updateSubscribedCommunitiesCache = (data: any) => { const userRole = data.userRole ? data.userRole : ''; const userLabel = data.userLabel ? data.userLabel : ''; - const subscribedCommunity:SubscribedCommunity = { - data : [data.communityId, communityTitle, userRole, userLabel, !data.isSubscribed], - expiresAt : created.getTime() + 86400000, + const subscribedCommunity: SubscribedCommunity = { + data: [data.communityId, communityTitle, userRole, userLabel, !data.isSubscribed], + expiresAt: created.getTime() + 86400000, }; - return ({ + return { payload: { path, - subscribedCommunity + subscribedCommunity, }, - type: UPDATE_SUBSCRIBED_COMMUNITY_CACHE - }) -} + type: UPDATE_SUBSCRIBED_COMMUNITY_CACHE, + }; +}; export const deleteSubscribedCommunityCacheEntry = (path: string) => ({ payload: path, - type: DELETE_SUBSCRIBED_COMMUNITY_CACHE -}) + type: DELETE_SUBSCRIBED_COMMUNITY_CACHE, +}); export const clearSubscribedCommunitiesCache = () => ({ - type: CLEAR_SUBSCRIBED_COMMUNITIES_CACHE -}) + type: CLEAR_SUBSCRIBED_COMMUNITIES_CACHE, +}); -export const updatePointActivityCache = (id:string, pointActivity: PointActivity) => ({ +export const updatePointActivityCache = (id: string, pointActivity: PointActivity) => ({ payload: { id, - pointActivity + pointActivity, }, - type: UPDATE_POINT_ACTIVITY_CACHE -}) + type: UPDATE_POINT_ACTIVITY_CACHE, +}); export const deletePointActivityCache = (id: string) => ({ payload: id, - type: DELETE_POINT_ACTIVITY_CACHE_ENTRY -}) + type: DELETE_POINT_ACTIVITY_CACHE_ENTRY, +}); export const purgeExpiredCache = () => ({ - type: PURGE_EXPIRED_CACHE -}) - + type: PURGE_EXPIRED_CACHE, +}); diff --git a/src/redux/actions/walletActions.ts b/src/redux/actions/walletActions.ts index fc1d2ab9f..8c6fc1908 100644 --- a/src/redux/actions/walletActions.ts +++ b/src/redux/actions/walletActions.ts @@ -1,82 +1,86 @@ import { getLatestQuotes } from '../../providers/ecency/ecency'; import { fetchCoinsData } from '../../utils/wallet'; -import { SET_SELECTED_COINS, SET_PRICE_HISTORY, SET_COINS_DATA, SET_COIN_ACTIVITIES, SET_COIN_QUOTES, RESET_WALLET_DATA } from '../constants/constants'; +import { + SET_SELECTED_COINS, + SET_PRICE_HISTORY, + SET_COINS_DATA, + SET_COIN_ACTIVITIES, + SET_COIN_QUOTES, + RESET_WALLET_DATA, +} from '../constants/constants'; import { CoinActivitiesCollection, CoinBase, CoinData } from '../reducers/walletReducer'; import { AppDispatch, RootState } from '../store/store'; export const setSelectedCoins = (coins: CoinBase[]) => ({ - payload: coins, - type: SET_SELECTED_COINS, + payload: coins, + type: SET_SELECTED_COINS, }); - - -export const setCoinsData = (data: { [key: string]: CoinData }, vsCurrency: string, username: string) => ({ - payload: { - data, - vsCurrency, - username, - }, - type: SET_COINS_DATA -}) +export const setCoinsData = ( + data: { [key: string]: CoinData }, + vsCurrency: string, + username: string, +) => ({ + payload: { + data, + vsCurrency, + username, + }, + type: SET_COINS_DATA, +}); export const setPriceHistory = (coinId: string, vsCurrency: string, data: number[]) => ({ - payload: { - id: coinId, - vsCurrency, - data - }, - type: SET_PRICE_HISTORY -}) + payload: { + id: coinId, + vsCurrency, + data, + }, + type: SET_PRICE_HISTORY, +}); export const setCoinActivities = (coinId: string, data: CoinActivitiesCollection) => ({ - payload: { - id: coinId, - data, - }, - type: SET_COIN_ACTIVITIES -}) + payload: { + id: coinId, + data, + }, + type: SET_COIN_ACTIVITIES, +}); export const resetWalletData = () => ({ - type: RESET_WALLET_DATA -}) - + type: RESET_WALLET_DATA, +}); export const fetchCoinQuotes = () => (dispatch, getState) => { - const currency = getState().application.currency; - console.log("fetching quotes for currency", currency) - getLatestQuotes(currency.currencyRate) - .then((quotes) => { - console.log("Fetched quotes", quotes) - dispatch({ - type: SET_COIN_QUOTES, - payload: { ...quotes }, - }) - }) -} + const currency = getState().application.currency; + console.log('fetching quotes for currency', currency); + getLatestQuotes(currency.currencyRate).then((quotes) => { + console.log('Fetched quotes', quotes); + dispatch({ + type: SET_COIN_QUOTES, + payload: { ...quotes }, + }); + }); +}; +export const fetchAndSetCoinsData = (refresh: boolean = false) => async ( + dispatch: AppDispatch, + getState: RootState, +) => { + const coins = getState().wallet.selectedCoins; + const quotes = getState().wallet.quotes; + const currentAccount = getState().account.currentAccount; + const currency = getState().application.currency; + const globalProps = getState().account.globalProps; + const coinsData = await fetchCoinsData({ + coins, + currentAccount, + vsCurrency: currency.currency, + currencyRate: currency.currencyRate, + globalProps, + quotes, + refresh, + }); -export const fetchAndSetCoinsData = (refresh: boolean = false) => async (dispatch: AppDispatch, getState: RootState) => { - const coins = getState().wallet.selectedCoins; - const quotes = getState().wallet.quotes; - const currentAccount = getState().account.currentAccount; - const currency = getState().application.currency; - const globalProps = getState().account.globalProps; - - const coinsData = await fetchCoinsData({ - coins, - currentAccount, - vsCurrency: currency.currency, - currencyRate: currency.currencyRate, - globalProps, - quotes, - refresh - }) - - return dispatch(setCoinsData( - coinsData, - currency.currency, - currentAccount.username - )) -} + return dispatch(setCoinsData(coinsData, currency.currency, currentAccount.username)); +}; diff --git a/src/redux/constants/communitiesConstants.ts b/src/redux/constants/communitiesConstants.ts index 9b9652c06..c093cfc07 100644 --- a/src/redux/constants/communitiesConstants.ts +++ b/src/redux/constants/communitiesConstants.ts @@ -1,6 +1,5 @@ export const statusMessage = { - PENDING : 'PENDING', - SUCCESS : 'SUCCESS', - FAIL : 'FAIL', + PENDING: 'PENDING', + SUCCESS: 'SUCCESS', + FAIL: 'FAIL', }; - \ No newline at end of file diff --git a/src/redux/reducers/accountReducer.ts b/src/redux/reducers/accountReducer.ts index d2f465411..8f0df8a7d 100644 --- a/src/redux/reducers/accountReducer.ts +++ b/src/redux/reducers/accountReducer.ts @@ -12,25 +12,23 @@ import { SET_GLOBAL_PROPS, } from '../constants/constants'; - export interface GlobalProps { - hivePerMVests:number; - base:number; - quote:number; - fundRecentClaims:number; - fundRewardBalance:number; - hbdPrintRate:number; + hivePerMVests: number; + base: number; + quote: number; + fundRecentClaims: number; + fundRewardBalance: number; + hbdPrintRate: number; } - interface AccountState { - isFetching:boolean; + isFetching: boolean; currentAccount: any; otherAccounts: any[]; hasError: boolean; errorMessage: string; isLogingOut: boolean; - globalProps:GlobalProps|null; + globalProps: GlobalProps | null; } const initialState: AccountState = { @@ -40,7 +38,7 @@ const initialState: AccountState = { hasError: false, errorMessage: null, isLogingOut: false, - globalProps: null + globalProps: null, }; export default function (state = initialState, action) { diff --git a/src/redux/reducers/cacheReducer.ts b/src/redux/reducers/cacheReducer.ts index c17baac29..0f72e7d07 100644 --- a/src/redux/reducers/cacheReducer.ts +++ b/src/redux/reducers/cacheReducer.ts @@ -1,235 +1,231 @@ -import { PointActivity } from "../../providers/ecency/ecency.types"; +import { PointActivity } from '../../providers/ecency/ecency.types'; import { - PURGE_EXPIRED_CACHE, - UPDATE_VOTE_CACHE, - UPDATE_COMMENT_CACHE, - DELETE_COMMENT_CACHE_ENTRY, - DELETE_DRAFT_CACHE_ENTRY, - UPDATE_DRAFT_CACHE, - UPDATE_SUBSCRIBED_COMMUNITY_CACHE, - DELETE_SUBSCRIBED_COMMUNITY_CACHE, - CLEAR_SUBSCRIBED_COMMUNITIES_CACHE, - UPDATE_POINT_ACTIVITY_CACHE, - DELETE_POINT_ACTIVITY_CACHE_ENTRY -} from "../constants/constants"; + PURGE_EXPIRED_CACHE, + UPDATE_VOTE_CACHE, + UPDATE_COMMENT_CACHE, + DELETE_COMMENT_CACHE_ENTRY, + DELETE_DRAFT_CACHE_ENTRY, + UPDATE_DRAFT_CACHE, + UPDATE_SUBSCRIBED_COMMUNITY_CACHE, + DELETE_SUBSCRIBED_COMMUNITY_CACHE, + CLEAR_SUBSCRIBED_COMMUNITIES_CACHE, + UPDATE_POINT_ACTIVITY_CACHE, + DELETE_POINT_ACTIVITY_CACHE_ENTRY, +} from '../constants/constants'; export enum CommentCacheStatus { - PENDING = 'PENDING', - POSTPONED = 'PUBLISHED', - DELETED = 'DELETED', + PENDING = 'PENDING', + POSTPONED = 'PUBLISHED', + DELETED = 'DELETED', } export interface Vote { - amount: number; - isDownvote: boolean; - incrementStep: number; - votedAt: number; - expiresAt: number; + amount: number; + isDownvote: boolean; + incrementStep: number; + votedAt: number; + expiresAt: number; } export interface Comment { - author: string, - permlink: string, - parent_author: string, - parent_permlink: string, - body?: string, - markdownBody: string, - author_reputation?: number, - total_payout?: number, - net_rshares?: number, - active_votes?: Array<{ rshares: number, voter: string }>, - json_metadata?: any, - isDeletable?: boolean, - created?: string, //handle created and updated separatly - updated?: string, - expiresAt?: number, - status: CommentCacheStatus + author: string; + permlink: string; + parent_author: string; + parent_permlink: string; + body?: string; + markdownBody: string; + author_reputation?: number; + total_payout?: number; + net_rshares?: number; + active_votes?: Array<{ rshares: number; voter: string }>; + json_metadata?: any; + isDeletable?: boolean; + created?: string; //handle created and updated separatly + updated?: string; + expiresAt?: number; + status: CommentCacheStatus; } export interface Draft { - author: string, - body: string, - title?: string, - tags?: string, - meta?: any, - created?: number, - updated?: number, - expiresAt?: number; + author: string; + body: string; + title?: string; + tags?: string; + meta?: any; + created?: number; + updated?: number; + expiresAt?: number; } export interface SubscribedCommunity { - data: Array, - expiresAt?: number; + data: Array; + expiresAt?: number; } - interface State { - votes: Map - comments: Map //TODO: handle comment array per post, if parent is same - drafts: Map - subscribedCommunities: Map - pointActivities: Map - lastUpdate: { - postPath: string, - updatedAt: number, - type: 'vote' | 'comment' | 'draft', - } + votes: Map; + comments: Map; //TODO: handle comment array per post, if parent is same + drafts: Map; + subscribedCommunities: Map; + pointActivities: Map; + lastUpdate: { + postPath: string; + updatedAt: number; + type: 'vote' | 'comment' | 'draft'; + }; } const initialState: State = { - votes: new Map(), - comments: new Map(), - drafts: new Map(), - subscribedCommunities: new Map(), - pointActivities: new Map(), - lastUpdate: null, + votes: new Map(), + comments: new Map(), + drafts: new Map(), + subscribedCommunities: new Map(), + pointActivities: new Map(), + lastUpdate: null, }; export default function (state = initialState, action) { - const { type, payload } = action; - switch (type) { - case UPDATE_VOTE_CACHE: - if (!state.votes) { - state.votes = new Map(); - } - state.votes.set(payload.postPath, payload.vote); - return { - ...state, //spread operator in requried here, otherwise persist do not register change - lastUpdate: { - postPath: payload.postPath, - updatedAt: new Date().getTime(), - type: 'vote', - } - }; + const { type, payload } = action; + switch (type) { + case UPDATE_VOTE_CACHE: + if (!state.votes) { + state.votes = new Map(); + } + state.votes.set(payload.postPath, payload.vote); + return { + ...state, //spread operator in requried here, otherwise persist do not register change + lastUpdate: { + postPath: payload.postPath, + updatedAt: new Date().getTime(), + type: 'vote', + }, + }; - case UPDATE_COMMENT_CACHE: - if (!state.comments) { - state.comments = new Map(); - } - state.comments.set(payload.commentPath, payload.comment); - return { - ...state, //spread operator in requried here, otherwise persist do not register change - lastUpdate: { - postPath: payload.commentPath, - updatedAt: new Date().getTime(), - type: 'comment' - } - }; + case UPDATE_COMMENT_CACHE: + if (!state.comments) { + state.comments = new Map(); + } + state.comments.set(payload.commentPath, payload.comment); + return { + ...state, //spread operator in requried here, otherwise persist do not register change + lastUpdate: { + postPath: payload.commentPath, + updatedAt: new Date().getTime(), + type: 'comment', + }, + }; - case DELETE_COMMENT_CACHE_ENTRY: - if (state.comments && state.comments.has(payload)) { - state.comments.delete(payload); - } - return { ...state } + case DELETE_COMMENT_CACHE_ENTRY: + if (state.comments && state.comments.has(payload)) { + state.comments.delete(payload); + } + return { ...state }; - case UPDATE_DRAFT_CACHE: - if (!state.drafts) { - state.drafts = new Map(); - } + case UPDATE_DRAFT_CACHE: + if (!state.drafts) { + state.drafts = new Map(); + } - const curTime = new Date().getTime(); - const curDraft = state.drafts.get(payload.id); - const payloadDraft = payload.draft; + const curTime = new Date().getTime(); + const curDraft = state.drafts.get(payload.id); + const payloadDraft = payload.draft; - payloadDraft.created = curDraft ? curDraft.created : curTime; - payloadDraft.updated = curTime; - payloadDraft.expiresAt = curTime + 604800000 // 7 days ms + payloadDraft.created = curDraft ? curDraft.created : curTime; + payloadDraft.updated = curTime; + payloadDraft.expiresAt = curTime + 604800000; // 7 days ms - state.drafts.set(payload.id, payloadDraft); - return { - ...state, //spread operator in requried here, otherwise persist do not register change - lastUpdate: { - postPath: payload.id, - updatedAt: new Date().getTime(), - type: 'draft', - }, - }; + state.drafts.set(payload.id, payloadDraft); + return { + ...state, //spread operator in requried here, otherwise persist do not register change + lastUpdate: { + postPath: payload.id, + updatedAt: new Date().getTime(), + type: 'draft', + }, + }; - case DELETE_DRAFT_CACHE_ENTRY: - if (state.drafts && state.drafts.has(payload)) { - state.drafts.delete(payload); - } - return { ...state } + case DELETE_DRAFT_CACHE_ENTRY: + if (state.drafts && state.drafts.has(payload)) { + state.drafts.delete(payload); + } + return { ...state }; - case UPDATE_SUBSCRIBED_COMMUNITY_CACHE: - if (!state.subscribedCommunities) { - state.subscribedCommunities = new Map(); - } - const subscribedCommunities = new Map(state.subscribedCommunities); - subscribedCommunities.set(payload.path, payload.subscribedCommunity); - return { - ...state, //spread operator in requried here, otherwise persist do not register change - subscribedCommunities: subscribedCommunities - }; + case UPDATE_SUBSCRIBED_COMMUNITY_CACHE: + if (!state.subscribedCommunities) { + state.subscribedCommunities = new Map(); + } + const subscribedCommunities = new Map(state.subscribedCommunities); + subscribedCommunities.set(payload.path, payload.subscribedCommunity); + return { + ...state, //spread operator in requried here, otherwise persist do not register change + subscribedCommunities: subscribedCommunities, + }; - case DELETE_SUBSCRIBED_COMMUNITY_CACHE: - if (state.subscribedCommunities && state.subscribedCommunities.has(payload)) { - state.subscribedCommunities.delete(payload); - } - return { ...state } + case DELETE_SUBSCRIBED_COMMUNITY_CACHE: + if (state.subscribedCommunities && state.subscribedCommunities.has(payload)) { + state.subscribedCommunities.delete(payload); + } + return { ...state }; - case CLEAR_SUBSCRIBED_COMMUNITIES_CACHE: - state.subscribedCommunities = new Map(); + case CLEAR_SUBSCRIBED_COMMUNITIES_CACHE: + state.subscribedCommunities = new Map(); - return { ...state } + return { ...state }; - case UPDATE_POINT_ACTIVITY_CACHE: - if (!state.pointActivities) { - state.pointActivities = new Map(); - } - state.pointActivities.set(payload.id, payload.pointActivity); - return { - ...state, //spread operator in requried here, otherwise persist do not register change - }; + case UPDATE_POINT_ACTIVITY_CACHE: + if (!state.pointActivities) { + state.pointActivities = new Map(); + } + state.pointActivities.set(payload.id, payload.pointActivity); + return { + ...state, //spread operator in requried here, otherwise persist do not register change + }; - case DELETE_POINT_ACTIVITY_CACHE_ENTRY: - if (state.pointActivities && state.pointActivities.has(payload)) { - state.pointActivities.delete(payload); - } - return { ...state } + case DELETE_POINT_ACTIVITY_CACHE_ENTRY: + if (state.pointActivities && state.pointActivities.has(payload)) { + state.pointActivities.delete(payload); + } + return { ...state }; - case PURGE_EXPIRED_CACHE: - const currentTime = new Date().getTime(); + case PURGE_EXPIRED_CACHE: + const currentTime = new Date().getTime(); - if (state.votes && state.votes.size) { - Array.from(state.votes).forEach((entry) => { - if (entry[1].expiresAt < currentTime) { - state.votes.delete(entry[0]); - } - }) - } + if (state.votes && state.votes.size) { + Array.from(state.votes).forEach((entry) => { + if (entry[1].expiresAt < currentTime) { + state.votes.delete(entry[0]); + } + }); + } - if (state.comments && state.comments.size) { - Array.from(state.comments).forEach((entry) => { - if (entry[1].expiresAt < currentTime) { - state.comments.delete(entry[0]); - } - }) - } + if (state.comments && state.comments.size) { + Array.from(state.comments).forEach((entry) => { + if (entry[1].expiresAt < currentTime) { + state.comments.delete(entry[0]); + } + }); + } - if (state.drafts && state.drafts.size) { - Array.from(state.drafts).forEach((entry) => { - if (entry[1].expiresAt < currentTime || !entry[1].body) { - state.drafts.delete(entry[0]); - } - }) + if (state.drafts && state.drafts.size) { + Array.from(state.drafts).forEach((entry) => { + if (entry[1].expiresAt < currentTime || !entry[1].body) { + state.drafts.delete(entry[0]); + } + }); + } + if (state.subscribedCommunities && state.subscribedCommunities.size) { + Array.from(state.subscribedCommunities).forEach((entry) => { + if (entry[1].expiresAt < currentTime) { + state.subscribedCommunities.delete(entry[0]); + } + }); + } - } - - if (state.subscribedCommunities && state.subscribedCommunities.size) { - Array.from(state.subscribedCommunities).forEach((entry) => { - if (entry[1].expiresAt < currentTime) { - state.subscribedCommunities.delete(entry[0]); - } - }) - } - - return { - ...state - } - default: - return state; - } + return { + ...state, + }; + default: + return state; + } } - diff --git a/src/redux/reducers/editorReducer.ts b/src/redux/reducers/editorReducer.ts index 4323791ca..13428e29b 100644 --- a/src/redux/reducers/editorReducer.ts +++ b/src/redux/reducers/editorReducer.ts @@ -1,37 +1,36 @@ -import { REMOVE_BENEFICIARIES, SET_BENEFICIARIES } from "../constants/constants"; +import { REMOVE_BENEFICIARIES, SET_BENEFICIARIES } from '../constants/constants'; export interface Beneficiary { - account:string, - weight:number, - isValid?:boolean, - autoPowerUp?: boolean, + account: string; + weight: number; + isValid?: boolean; + autoPowerUp?: boolean; } interface State { - beneficiariesMap:{ - [key: string]: Beneficiary[] - } + beneficiariesMap: { + [key: string]: Beneficiary[]; + }; } -const initialState:State = { - beneficiariesMap:{} - }; - - export default function (state = initialState, action) { - const {type, payload} = action; - switch (type) { - case SET_BENEFICIARIES: - state.beneficiariesMap[payload.draftId] = payload.benficiaries; - return { - ...state //spread operator in requried here, otherwise persist do not register change - }; - case REMOVE_BENEFICIARIES: - delete state.beneficiariesMap[payload.draftId] - return { - ...state //spread operator in requried here, otherwise persist do not register change - }; - default: - return state; - } - } +const initialState: State = { + beneficiariesMap: {}, +}; +export default function (state = initialState, action) { + const { type, payload } = action; + switch (type) { + case SET_BENEFICIARIES: + state.beneficiariesMap[payload.draftId] = payload.benficiaries; + return { + ...state, //spread operator in requried here, otherwise persist do not register change + }; + case REMOVE_BENEFICIARIES: + delete state.beneficiariesMap[payload.draftId]; + return { + ...state, //spread operator in requried here, otherwise persist do not register change + }; + default: + return state; + } +} diff --git a/src/redux/reducers/walletReducer.ts b/src/redux/reducers/walletReducer.ts index 9841b9d6c..607d60b35 100644 --- a/src/redux/reducers/walletReducer.ts +++ b/src/redux/reducers/walletReducer.ts @@ -1,140 +1,144 @@ -import DEFAULT_COINS from "../../constants/defaultCoins"; -import { SET_PRICE_HISTORY, SET_SELECTED_COINS, SET_COINS_DATA, SET_COIN_ACTIVITIES, SET_COIN_QUOTES, RESET_WALLET_DATA } from "../constants/constants"; +import DEFAULT_COINS from '../../constants/defaultCoins'; +import { + SET_PRICE_HISTORY, + SET_SELECTED_COINS, + SET_COINS_DATA, + SET_COIN_ACTIVITIES, + SET_COIN_QUOTES, + RESET_WALLET_DATA, +} from '../constants/constants'; export interface DataPair { - value:string|number; - dataKey:string; - isClickable?:boolean; + value: string | number; + dataKey: string; + isClickable?: boolean; } export interface CoinBase { - id:string, - symbol:string, - notCrypto:boolean, + id: string; + symbol: string; + notCrypto: boolean; } export interface CoinData { - currentPrice:number; - balance:number; - savings?:number; - unclaimedBalance:string, - estimateValue?:number; - vsCurrency:string; - actions:string[]; - extraDataPairs?:DataPair[]; + currentPrice: number; + balance: number; + savings?: number; + unclaimedBalance: string; + estimateValue?: number; + vsCurrency: string; + actions: string[]; + extraDataPairs?: DataPair[]; } export interface PriceHistory { - expiresAt:number; - vsCurrency:string; - data:number[]; + expiresAt: number; + vsCurrency: string; + data: number[]; } export interface CoinActivity { - trxIndex:number; - iconType: string; - textKey: string; - created: string; - expires: string; - icon: string; - value:string; - details: string; - memo: string; + trxIndex: number; + iconType: string; + textKey: string; + created: string; + expires: string; + icon: string; + value: string; + details: string; + memo: string; } export interface QuoteItem { - lastUpdated:string; - percentChange:number; - price:number; + lastUpdated: string; + percentChange: number; + price: number; } export interface CoinActivitiesCollection { - completed:CoinActivity[], - pending:CoinActivity[], + completed: CoinActivity[]; + pending: CoinActivity[]; } - interface State { - selectedCoins:CoinBase[]; - coinsData:{ - [key: string]: CoinData; - }, - priceHistories:{ - [key: string]: PriceHistory; - } - coinsActivities:{ - [key: string]:CoinActivitiesCollection; - }, - quotes:{ - [key: string]: QuoteItem; - } - vsCurrency:string, - username:string, - updateTimestamp:number; + selectedCoins: CoinBase[]; + coinsData: { + [key: string]: CoinData; + }; + priceHistories: { + [key: string]: PriceHistory; + }; + coinsActivities: { + [key: string]: CoinActivitiesCollection; + }; + quotes: { + [key: string]: QuoteItem; + }; + vsCurrency: string; + username: string; + updateTimestamp: number; } - - -const initialState:State = { - selectedCoins:DEFAULT_COINS, - coinsData:{}, - priceHistories:{}, - coinsActivities:{}, - quotes: null, - vsCurrency:'', - username:'', - updateTimestamp:0 +const initialState: State = { + selectedCoins: DEFAULT_COINS, + coinsData: {}, + priceHistories: {}, + coinsActivities: {}, + quotes: null, + vsCurrency: '', + username: '', + updateTimestamp: 0, }; - + export default function (state = initialState, action) { - const {type, payload} = action; - switch (type) { - case RESET_WALLET_DATA:{ - return { - ...initialState, - selectedCoins:state.selectedCoins - } + const { type, payload } = action; + switch (type) { + case RESET_WALLET_DATA: { + return { + ...initialState, + selectedCoins: state.selectedCoins, + }; } - case SET_SELECTED_COINS:{ - return { - ...state, - selectedCoin:payload - } + case SET_SELECTED_COINS: { + return { + ...state, + selectedCoin: payload, + }; } - case SET_COINS_DATA:{ - return { - ...state, - coinsData:payload.data, - vsCurrency:payload.vsCurrency, - username:payload.username, - updateTimestamp:new Date().getTime() - } + case SET_COINS_DATA: { + return { + ...state, + coinsData: payload.data, + vsCurrency: payload.vsCurrency, + username: payload.username, + updateTimestamp: new Date().getTime(), + }; } - case SET_PRICE_HISTORY:{ - state.priceHistories[payload.id] = { - expiresAt:new Date().getTime() + ONE_HOUR_MS, - vsCurrency:payload.vsCurrency, - data:payload.data - }; - return { - ...state - } + case SET_PRICE_HISTORY: { + state.priceHistories[payload.id] = { + expiresAt: new Date().getTime() + ONE_HOUR_MS, + vsCurrency: payload.vsCurrency, + data: payload.data, + }; + return { + ...state, + }; } - case SET_COIN_ACTIVITIES:{ - state.coinsActivities[payload.id] = payload.data - return { - ...state - } + case SET_COIN_ACTIVITIES: { + state.coinsActivities[payload.id] = payload.data; + return { + ...state, + }; } - case SET_COIN_QUOTES:{ - return { - ...state, - quotes:payload, - } + case SET_COIN_QUOTES: { + return { + ...state, + quotes: payload, + }; } default: - return state; - } + return state; + } } -const ONE_HOUR_MS = 60 * 60 * 1000; \ No newline at end of file +const ONE_HOUR_MS = 60 * 60 * 1000; diff --git a/src/redux/store/store.ts b/src/redux/store/store.ts index d34e3b3b2..c0bb99db8 100644 --- a/src/redux/store/store.ts +++ b/src/redux/store/store.ts @@ -23,7 +23,7 @@ const transformCacheVoteMap = createTransform( comments: new Map(outboundState.comments), drafts: new Map(outboundState.drafts), subscribedCommunities: new Map(outboundState.subscribedCommunities), - pointActivities: new Map(outboundState.pointActivities) + pointActivities: new Map(outboundState.pointActivities), }), { whitelist: ['cache'] }, ); diff --git a/src/screens/application/children/applicationScreen.tsx b/src/screens/application/children/applicationScreen.tsx index ac182f370..6150e839b 100644 --- a/src/screens/application/children/applicationScreen.tsx +++ b/src/screens/application/children/applicationScreen.tsx @@ -3,8 +3,6 @@ import { StatusBar, Platform, View, Alert, Text } from 'react-native'; import EStyleSheet from 'react-native-extended-stylesheet'; import { connect } from 'react-redux'; - - import { injectIntl } from 'react-intl'; import { AppNavigator } from '../../../navigation'; @@ -34,7 +32,6 @@ import { import darkTheme from '../../../themes/darkTheme'; import lightTheme from '../../../themes/lightTheme'; - class ApplicationScreen extends Component { constructor(props) { super(props); @@ -97,7 +94,6 @@ class ApplicationScreen extends Component { } } - _renderStatusBar() { const { isDarkTheme } = this.props; const barStyle = isDarkTheme ? 'light-content' : 'dark-content'; @@ -110,10 +106,9 @@ class ApplicationScreen extends Component { )} - ) + ); } - _renderAppNavigator() { const { isConnected } = this.props; return ( @@ -121,17 +116,14 @@ class ApplicationScreen extends Component { {!isConnected && } - - ) + ); } - - _renderAppModals() { const { toastNotification, foregroundNotificationData } = this.props; const { isShowToastNotification } = this.state; - + return ( <> @@ -148,11 +140,9 @@ class ApplicationScreen extends Component { /> )} - ) + ); } - - render() { return ( diff --git a/src/screens/application/hook/useInitApplication.tsx b/src/screens/application/hook/useInitApplication.tsx index ad2eee4ea..141296af9 100644 --- a/src/screens/application/hook/useInitApplication.tsx +++ b/src/screens/application/hook/useInitApplication.tsx @@ -2,6 +2,7 @@ import { useEffect, useRef } from 'react'; import Orientation, { useDeviceOrientationChange } from 'react-native-orientation-locker'; import { isLandscape } from 'react-native-device-info'; import EStyleSheet from 'react-native-extended-stylesheet'; +import { AppState } from 'react-native'; import { useAppDispatch, useAppSelector } from '../../../hooks'; import { setDeviceOrientation, setLockedOrientation } from '../../../redux/actions/uiAction'; import { orientations } from '../../../redux/constants/orientationsConstants'; @@ -9,9 +10,6 @@ import isAndroidTablet from '../../../utils/isAndroidTablet'; import darkTheme from '../../../themes/darkTheme'; import lightTheme from '../../../themes/lightTheme'; import { useUserActivityMutation } from '../../../providers/queries'; -import { AppState } from 'react-native'; - - export const useInitApplication = () => { const dispatch = useAppDispatch(); @@ -47,21 +45,15 @@ export const useInitApplication = () => { return _cleanup; }, []); - const _cleanup = () => { AppState.removeEventListener('change', _handleAppStateChange); - } - + }; const _handleAppStateChange = (nextAppState) => { - if (appState.current.match(/inactive|background/) && nextAppState === 'active') { - userActivityMutation.lazyMutatePendingActivities(); - } appState.current = nextAppState; - }; }; diff --git a/src/screens/boost/screen/styles.ts b/src/screens/boost/screen/styles.ts index 6a7a8441a..464ad4ac4 100644 --- a/src/screens/boost/screen/styles.ts +++ b/src/screens/boost/screen/styles.ts @@ -2,14 +2,14 @@ import { ViewStyle } from 'react-native'; import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ - userRibbonContainer: { - borderBottomWidth: EStyleSheet.hairlineWidth, - borderColor: '$darkGrayBackground', - marginBottom: 0, //without 0 margin, view will start overlapping UserRibbon - paddingBottom: 32 - } as ViewStyle, + userRibbonContainer: { + borderBottomWidth: EStyleSheet.hairlineWidth, + borderColor: '$darkGrayBackground', + marginBottom: 0, //without 0 margin, view will start overlapping UserRibbon + paddingBottom: 32, + } as ViewStyle, - listContainer: { - paddingTop: 16 - } as ViewStyle + listContainer: { + paddingTop: 16, + } as ViewStyle, }); diff --git a/src/screens/coinDetails/children/activitiesList.tsx b/src/screens/coinDetails/children/activitiesList.tsx index 0e4f8bb29..34a4d6e9a 100644 --- a/src/screens/coinDetails/children/activitiesList.tsx +++ b/src/screens/coinDetails/children/activitiesList.tsx @@ -1,4 +1,4 @@ -import React, { ComponentType, JSXElementConstructor, ReactElement } from 'react' +import React, { ComponentType, JSXElementConstructor, ReactElement } from 'react'; import { useIntl } from 'react-intl'; import { SectionList, Text, RefreshControl, ActivityIndicator } from 'react-native'; import { Transaction } from '../../../components'; @@ -7,7 +7,7 @@ import { CoinActivity } from '../../../redux/reducers/walletReducer'; import styles from './children.styles'; interface ActivitiesListProps { - header: ComponentType | ReactElement> + header: ComponentType | ReactElement>; pendingActivities: CoinActivity[]; completedActivities: CoinActivity[]; refreshing: boolean; @@ -16,7 +16,6 @@ interface ActivitiesListProps { onRefresh: () => void; } - const ActivitiesList = ({ header, loading, @@ -24,31 +23,29 @@ const ActivitiesList = ({ completedActivities, pendingActivities, onEndReached, - onRefresh + onRefresh, }: ActivitiesListProps) => { const intl = useIntl(); - const isDarkTheme = useAppSelector(state => state.ui.isDarkTheme); + const isDarkTheme = useAppSelector((state) => state.ui.isDarkTheme); const _renderActivityItem = ({ item, index }) => { - return - } + return ; + }; const sections = []; if (pendingActivities && pendingActivities.length) { sections.push({ title: intl.formatMessage({ id: 'wallet.pending_requests' }), - data: pendingActivities - }) + data: pendingActivities, + }); } - sections.push({ title: intl.formatMessage({ id: 'wallet.activities' }), - data: completedActivities || [] - }) - + data: completedActivities || [], + }); const _refreshControl = ( - ) - + ); return ( ( {title} )} - ListFooterComponent={loading && } + ListFooterComponent={ + loading && + } ListHeaderComponent={header} refreshControl={_refreshControl} - onEndReached={()=>{onEndReached()}} + onEndReached={() => { + onEndReached(); + }} /> - ) -} - -export default ActivitiesList - + ); +}; +export default ActivitiesList; diff --git a/src/screens/coinDetails/children/children.styles.ts b/src/screens/coinDetails/children/children.styles.ts index 5c611807a..353cca1aa 100644 --- a/src/screens/coinDetails/children/children.styles.ts +++ b/src/screens/coinDetails/children/children.styles.ts @@ -1,147 +1,143 @@ import { TextStyle, ViewStyle } from 'react-native'; import EStyleSheet from 'react-native-extended-stylesheet'; -export const CHART_NEGATIVE_MARGIN = 12 +export const CHART_NEGATIVE_MARGIN = 12; export default EStyleSheet.create({ - card: { - marginVertical:8, - borderRadius:12, + marginVertical: 8, + borderRadius: 12, overflow: 'hidden', - backgroundColor: '$primaryLightBackground' + backgroundColor: '$primaryLightBackground', } as ViewStyle, - basicsContainer:{ - alignItems:'center', - padding:16 + basicsContainer: { + alignItems: 'center', + padding: 16, } as ViewStyle, - coinTitleContainer:{ - flexDirection:'row', - marginTop:8 + coinTitleContainer: { + flexDirection: 'row', + marginTop: 8, } as ViewStyle, - textCoinTitle:{ - color: '$primaryBlack', + textCoinTitle: { + color: '$primaryBlack', fontSize: 34, - fontWeight:'700', + fontWeight: '700', } as TextStyle, - textHeaderChange:{ + textHeaderChange: { color: '$primaryDarkText', fontSize: 16, - marginBottom:32, + marginBottom: 32, } as TextStyle, - - textPositive:{ - color: '$primaryGreen' - } as TextStyle, - textNegative:{ - color: '$primaryRed' - } as TextStyle, - textBasicValue:{ - color: '$primaryBlack', - fontWeight:'700', - fontSize: 28, + textPositive: { + color: '$primaryGreen', } as TextStyle, - textBasicLabel:{ + textNegative: { + color: '$primaryRed', + } as TextStyle, + textBasicValue: { + color: '$primaryBlack', + fontWeight: '700', + fontSize: 28, + } as TextStyle, + textBasicLabel: { color: '$primaryDarkText', fontSize: 14, - marginBottom:16, + marginBottom: 16, } as TextStyle, - extraDataContainer:{ - flexDirection:'row', + extraDataContainer: { + flexDirection: 'row', justifyContent: 'space-between', - alignItems:'center', - width:'100%', + alignItems: 'center', + width: '100%', marginVertical: 2, } as ViewStyle, - textExtraValue:{ + textExtraValue: { color: '$primaryDarkText', - fontWeight:'700', + fontWeight: '700', fontSize: 18, - } as TextStyle, - textExtraLabel:{ + textExtraLabel: { color: '$primaryDarkText', fontSize: 14, } as TextStyle, - rangeContainer:{ - flexDirection:'row', - alignItems:'center', - justifyContent:'space-between', - borderRadius:32, + rangeContainer: { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'space-between', + borderRadius: 32, } as ViewStyle, - rangeOptionWrapper:{ - borderRadius:32, - paddingVertical:16, - paddingHorizontal:24 + rangeOptionWrapper: { + borderRadius: 32, + paddingVertical: 16, + paddingHorizontal: 24, } as ViewStyle, - textRange:{ - fontSize:16, + textRange: { + fontSize: 16, } as TextStyle, - chartContainer:{ + chartContainer: { height: 168, marginTop: 16, - marginLeft:-CHART_NEGATIVE_MARGIN, + marginLeft: -CHART_NEGATIVE_MARGIN, overflow: 'hidden', } as ViewStyle, - list:{ - flex:1, + list: { + flex: 1, + } as ViewStyle, + listContent: { + paddingBottom: 56, + paddingHorizontal: 16, } as ViewStyle, - listContent:{ - paddingBottom:56, - paddingHorizontal:16, - } as ViewStyle , //COIN ACTIONS STYLES - actionBtnContainer:{ - flexGrow:1 + actionBtnContainer: { + flexGrow: 1, } as ViewStyle, - actionsContainer:{ - flexDirection:'row', - flexWrap:'wrap' + actionsContainer: { + flexDirection: 'row', + flexWrap: 'wrap', } as ViewStyle, - actionContainer:{ - paddingHorizontal:16, - marginVertical:8, - marginHorizontal:4, - backgroundColor:'$primaryLightBackground', + actionContainer: { + paddingHorizontal: 16, + marginVertical: 8, + marginHorizontal: 4, + backgroundColor: '$primaryLightBackground', height: 40, - borderRadius:20, - justifyContent:'center', - alignItems:'center', + borderRadius: 20, + justifyContent: 'center', + alignItems: 'center', } as ViewStyle, - actionText:{ - color: '$primaryBlack' + actionText: { + color: '$primaryBlack', } as TextStyle, - textActivities:{ - color:'$primaryBlack', - fontWeight:'600', - fontSize:18, - paddingVertical:16, - backgroundColor:'$primaryBackgroundColor', + textActivities: { + color: '$primaryBlack', + fontWeight: '600', + fontSize: 18, + paddingVertical: 16, + backgroundColor: '$primaryBackgroundColor', textAlign: 'left', } as TextStyle, - activitiesFooterIndicator:{ - marginVertical: 16 + activitiesFooterIndicator: { + marginVertical: 16, } as ViewStyle, - delegationsModal:{ + delegationsModal: { flex: 1, backgroundColor: '$primaryBackgroundColor', margin: 0, paddingTop: 32, paddingBottom: 16, }, - textUnderline:{ - textDecorationLine:'underline', - textDecorationColor:'$primaryDarkText' - } + textUnderline: { + textDecorationLine: 'underline', + textDecorationColor: '$primaryDarkText', + }, }); - diff --git a/src/screens/coinDetails/children/coinActions.tsx b/src/screens/coinDetails/children/coinActions.tsx index e5f612438..c44753826 100644 --- a/src/screens/coinDetails/children/coinActions.tsx +++ b/src/screens/coinDetails/children/coinActions.tsx @@ -1,38 +1,36 @@ -import React, { Fragment } from 'react' -import { useIntl } from 'react-intl' -import { View, Text } from 'react-native' -import { TouchableOpacity } from 'react-native-gesture-handler' -import { withNavigation } from '@react-navigation/compat' -import styles from './children.styles' +import React, { Fragment } from 'react'; +import { useIntl } from 'react-intl'; +import { View, Text } from 'react-native'; +import { TouchableOpacity } from 'react-native-gesture-handler'; +import { withNavigation } from '@react-navigation/compat'; +import styles from './children.styles'; interface CoinActionsProps { - actions: string[]; - onActionPress: (action: string) => void; + actions: string[]; + onActionPress: (action: string) => void; } export const CoinActions = withNavigation(({ actions, onActionPress }: CoinActionsProps) => { - const intl = useIntl(); + const intl = useIntl(); - const _renderItem = (item: string, index: number) => { - - const _onPress = () => { - onActionPress(item) - } - - return ( - - - - {intl.formatMessage({ id: `wallet.${item}` })} - - - - ) - } + const _renderItem = (item: string, index: number) => { + const _onPress = () => { + onActionPress(item); + }; return ( - - {actions.map(_renderItem)} - - ) -}); \ No newline at end of file + + + {intl.formatMessage({ id: `wallet.${item}` })} + + + ); + }; + + return {actions.map(_renderItem)}; +}); diff --git a/src/screens/coinDetails/children/coinBasics.tsx b/src/screens/coinDetails/children/coinBasics.tsx index 8a860b764..8e20db222 100644 --- a/src/screens/coinDetails/children/coinBasics.tsx +++ b/src/screens/coinDetails/children/coinBasics.tsx @@ -1,76 +1,77 @@ -import React, { Fragment } from 'react' +import React, { Fragment } from 'react'; import { useIntl } from 'react-intl'; -import { View, Text, Alert } from 'react-native' +import { View, Text, Alert } from 'react-native'; import { TouchableOpacity } from 'react-native-gesture-handler'; -import { DataPair } from '../../../redux/reducers/walletReducer' -import styles from './children.styles' - +import { DataPair } from '../../../redux/reducers/walletReducer'; +import styles from './children.styles'; interface CoinBasicsProps { - valuePairs: DataPair[]; - extraData: DataPair[]; - coinSymbol: string; - percentChange: number; - onInfoPress: (id:string)=>void + valuePairs: DataPair[]; + extraData: DataPair[]; + coinSymbol: string; + percentChange: number; + onInfoPress: (id: string) => void; } -export const CoinBasics = ({ valuePairs, extraData, coinSymbol, percentChange, onInfoPress}: CoinBasicsProps) => { - const intl = useIntl(); - const _renderCoinHeader = ( - <> - - {coinSymbol} - - - {intl.formatMessage({ id: 'wallet.change' })} - 0 ? styles.textPositive : styles.textNegative}> - {` ${percentChange >= 0 ? '+' : ''}${percentChange.toFixed(1)}%`} - +export const CoinBasics = ({ + valuePairs, + extraData, + coinSymbol, + percentChange, + onInfoPress, +}: CoinBasicsProps) => { + const intl = useIntl(); + const _renderCoinHeader = ( + <> + + {coinSymbol} + + + {intl.formatMessage({ id: 'wallet.change' })} + 0 ? styles.textPositive : styles.textNegative}> + {` ${percentChange >= 0 ? '+' : ''}${percentChange.toFixed(1)}%`} + + + + ); - - - ) + const _renderValuePair = (args: DataPair, index: number) => { + const label = intl.formatMessage({ id: `wallet.${args.dataKey}` }); + return ( + + {args.value} + {label} + + ); + }; - const _renderValuePair = (args: DataPair, index: number) => { - const label = intl.formatMessage({ id: `wallet.${args.dataKey}` }) - return ( - - {args.value} - {label} - - ) - } + const _renderExtraData = (args: DataPair, index: number) => { + const label = intl.formatMessage({ id: `wallet.${args.dataKey || args.labelId}` }); - const _renderExtraData = (args: DataPair, index: number) => { - const label = intl.formatMessage({ id: `wallet.${args.dataKey || args.labelId}` }) - - const _onPress = () => { - onInfoPress(args.dataKey); - } - - return ( - - - {label} - - - {args.value} - - - ) - } + const _onPress = () => { + onInfoPress(args.dataKey); + }; return ( - - {_renderCoinHeader} - {valuePairs.map(_renderValuePair)} - {extraData && extraData.map(_renderExtraData)} - - ) -} + + + {label} + + + {args.value} + + + ); + }; + + return ( + + {_renderCoinHeader} + {valuePairs.map(_renderValuePair)} + {extraData && extraData.map(_renderExtraData)} + + ); +}; diff --git a/src/screens/coinDetails/children/coinChart.tsx b/src/screens/coinDetails/children/coinChart.tsx index ea22c9deb..1e3cde600 100644 --- a/src/screens/coinDetails/children/coinChart.tsx +++ b/src/screens/coinDetails/children/coinChart.tsx @@ -1,54 +1,50 @@ -import React, { useState, useEffect } from 'react' -import { View } from 'react-native' +import React, { useState, useEffect } from 'react'; +import { View } from 'react-native'; import { RangeSelector } from '.'; -import { SimpleChart } from '../../../components' +import { SimpleChart } from '../../../components'; import { useAppSelector } from '../../../hooks'; import { fetchMarketChart } from '../../../providers/coingecko/coingecko'; import getWindowDimensions from '../../../utils/getWindowDimensions'; import styles, { CHART_NEGATIVE_MARGIN } from './children.styles'; - interface CoinChartProps { - coinId:string; + coinId: string; } -export const CoinChart = ({coinId}:CoinChartProps) => { - - const priceHistory = useAppSelector(state=>state.wallet.priceHistories[coinId]); +export const CoinChart = ({ coinId }: CoinChartProps) => { + const priceHistory = useAppSelector((state) => state.wallet.priceHistories[coinId]); const [range, setRange] = useState(1); const [chartData, setChartData] = useState(priceHistory?.data); - const _fetchMarketData = async (days:number) => { - const marketData = await fetchMarketChart(coinId, 'usd', days, 'hourly') - setChartData(marketData.prices.map(item=>item.yValue)); - } - + const _fetchMarketData = async (days: number) => { + const marketData = await fetchMarketChart(coinId, 'usd', days, 'hourly'); + setChartData(marketData.prices.map((item) => item.yValue)); + }; const _onRangeChange = (range) => { setRange(range); _fetchMarketData(range); - } + }; - const _renderGraph = () => { - const _baseWidth = getWindowDimensions().width - 32 + CHART_NEGATIVE_MARGIN; - return ( - - - - )} + const _renderGraph = () => { + const _baseWidth = getWindowDimensions().width - 32 + CHART_NEGATIVE_MARGIN; return ( - <> - - {_renderGraph()} - - - - ) -} \ No newline at end of file + + + + ); + }; + return ( + <> + {_renderGraph()} + + + ); +}; diff --git a/src/screens/coinDetails/children/coinSummary.tsx b/src/screens/coinDetails/children/coinSummary.tsx index 0855d85fe..4bd207761 100644 --- a/src/screens/coinDetails/children/coinSummary.tsx +++ b/src/screens/coinDetails/children/coinSummary.tsx @@ -1,69 +1,61 @@ -import React from 'react' -import { View } from 'react-native' -import { CoinActions, CoinBasics, CoinChart } from '.' -import { FormattedCurrency } from '../../../components' -import { COIN_IDS } from '../../../constants/defaultCoins' -import { CoinData, DataPair } from '../../../redux/reducers/walletReducer' +import React from 'react'; +import { View } from 'react-native'; +import { CoinActions, CoinBasics, CoinChart } from '.'; +import { FormattedCurrency } from '../../../components'; +import { COIN_IDS } from '../../../constants/defaultCoins'; +import { CoinData, DataPair } from '../../../redux/reducers/walletReducer'; export interface CoinSummaryProps { - id:string; - coinSymbol:string; - coinData:CoinData; - percentChagne:number; - onActionPress:(action:string)=>void; - onInfoPress:(dataKey:string)=>void; + id: string; + coinSymbol: string; + coinData: CoinData; + percentChagne: number; + onActionPress: (action: string) => void; + onInfoPress: (dataKey: string) => void; } export const CoinSummary = ({ - coinSymbol, - id, - coinData, - percentChagne, - onActionPress, - onInfoPress -}:CoinSummaryProps) => { - const { - balance, - estimateValue, - savings, - extraDataPairs, - actions - } = coinData + coinSymbol, + id, + coinData, + percentChagne, + onActionPress, + onInfoPress, +}: CoinSummaryProps) => { + const { balance, estimateValue, savings, extraDataPairs, actions } = coinData; - const valuePairs = [ - { - dataKey:'amount_desc', - value:balance - } - ] as DataPair[] + const valuePairs = [ + { + dataKey: 'amount_desc', + value: balance, + }, + ] as DataPair[]; - if(estimateValue !== undefined){ - valuePairs.push({ - dataKey:'estimated_value', - value:, - }) - } + if (estimateValue !== undefined) { + valuePairs.push({ + dataKey: 'estimated_value', + value: , + }); + } - if(savings !== undefined){ - valuePairs.push({ - dataKey:'savings', - value:savings - }) - } + if (savings !== undefined) { + valuePairs.push({ + dataKey: 'savings', + value: savings, + }); + } - return ( - - - - { - id !== COIN_IDS.ECENCY && id !== COIN_IDS.HP && - } - - ) -} + return ( + + + + {id !== COIN_IDS.ECENCY && id !== COIN_IDS.HP && } + + ); +}; diff --git a/src/screens/coinDetails/children/delegationsModal.tsx b/src/screens/coinDetails/children/delegationsModal.tsx index 5104f9fee..ede3d6e17 100644 --- a/src/screens/coinDetails/children/delegationsModal.tsx +++ b/src/screens/coinDetails/children/delegationsModal.tsx @@ -1,210 +1,207 @@ -import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react' -import AccountListContainer from '../../../containers/accountListContainer' -import { useIntl } from 'react-intl' -import { FlatList } from 'react-native-gesture-handler' -import { useNavigation } from '@react-navigation/native' -import ROUTES from '../../../constants/routeNames' -import { StackNavigationProp } from '@react-navigation/stack' +import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'; +import { useIntl } from 'react-intl'; +import { FlatList } from 'react-native-gesture-handler'; +import { useNavigation } from '@react-navigation/native'; +import { StackNavigationProp } from '@react-navigation/stack'; +import { RefreshControl } from 'react-native'; +import unionBy from 'lodash/unionBy'; +import AccountListContainer from '../../../containers/accountListContainer'; +import ROUTES from '../../../constants/routeNames'; import styles from './children.styles'; -import { BasicHeader, Modal, UserListItem } from '../../../components' -import { useAppSelector } from '../../../hooks' -import { getVestingDelegations } from '../../../providers/hive/dhive' -import { RefreshControl } from 'react-native' -import { getReceivedVestingShares } from '../../../providers/ecency/ecency' -import { vestsToHp } from '../../../utils/conversions' -import unionBy from 'lodash/unionBy' +import { BasicHeader, Modal, UserListItem } from '../../../components'; +import { useAppSelector } from '../../../hooks'; +import { getVestingDelegations } from '../../../providers/hive/dhive'; +import { getReceivedVestingShares } from '../../../providers/ecency/ecency'; +import { vestsToHp } from '../../../utils/conversions'; export enum MODES { - DELEGATEED = 'delegated_hive_power', - RECEIVED = 'received_hive_power', + DELEGATEED = 'delegated_hive_power', + RECEIVED = 'received_hive_power', } interface DelegationItem { - username: string; - vestingShares: string; - timestamp: string; + username: string; + vestingShares: string; + timestamp: string; } -export const DelegationsModal = forwardRef(({ }, ref) => { - const intl = useIntl(); - const navigation = useNavigation>(); +export const DelegationsModal = forwardRef(({}, ref) => { + const intl = useIntl(); + const navigation = useNavigation>(); - const currentAccount = useAppSelector(state => state.account.currentAccount); - const globalProps = useAppSelector(state => state.account.globalProps); - const isDarkTheme = useAppSelector(state => state.application.isDarkTheme); + const currentAccount = useAppSelector((state) => state.account.currentAccount); + const globalProps = useAppSelector((state) => state.account.globalProps); + const isDarkTheme = useAppSelector((state) => state.application.isDarkTheme); - const [delegations, setDelegations] = useState([]); - const [showModal, setShowModal] = useState(false); - const [mode, setMode] = useState(MODES.DELEGATEED); - const [isLoading, setIsLoading] = useState(false); + const [delegations, setDelegations] = useState([]); + const [showModal, setShowModal] = useState(false); + const [mode, setMode] = useState(MODES.DELEGATEED); + const [isLoading, setIsLoading] = useState(false); - useImperativeHandle(ref, () => ({ - showModal: (_mode: MODES) => { - setDelegations([]) - setShowModal(true) - setMode(_mode) - } - })) + useImperativeHandle(ref, () => ({ + showModal: (_mode: MODES) => { + setDelegations([]); + setShowModal(true); + setMode(_mode); + }, + })); - useEffect(() => { - if (showModal) { - _getDelegations() - } - }, [mode, showModal]) + useEffect(() => { + if (showModal) { + _getDelegations(); + } + }, [mode, showModal]); + const _getVestingDelegations = async (startUsername: string = '') => { + let resData: any = []; + let limit = 1000; - const _getVestingDelegations = async (startUsername: string = '') => { - let resData:any = [] - let limit = 1000; + const response = await getVestingDelegations(currentAccount.username, startUsername, limit); + resData = response.map( + (item) => + ({ + username: item.delegatee, + vestingShares: item.vesting_shares, + timestamp: item.min_delegation_time, + } as DelegationItem), + ); - const response = await getVestingDelegations(currentAccount.username, startUsername, limit); - resData = response.map((item) => ({ - username: item.delegatee, - vestingShares: item.vesting_shares, - timestamp: item.min_delegation_time - } as DelegationItem)) - - if (resData.length === limit) { - const data = await _getVestingDelegations(response[response.length - 1].delegatee) - resData = unionBy(resData, data, 'username') - } - - - return resData; + if (resData.length === limit) { + const data = await _getVestingDelegations(response[response.length - 1].delegatee); + resData = unionBy(resData, data, 'username'); } - const _getReceivedDelegations = async () => { - const response = await getReceivedVestingShares(currentAccount.username) - return response.map((item) => ({ - username: item.delegator, - vestingShares: item.vesting_shares, - timestamp: item.timestamp - })) + return resData; + }; + + const _getReceivedDelegations = async () => { + const response = await getReceivedVestingShares(currentAccount.username); + return response.map((item) => ({ + username: item.delegator, + vestingShares: item.vesting_shares, + timestamp: item.timestamp, + })); + }; + + const _getDelegations = async () => { + try { + setIsLoading(true); + let response: DelegationItem[] = []; + switch (mode) { + case MODES.DELEGATEED: + response = await _getVestingDelegations(); + break; + case MODES.RECEIVED: + response = await _getReceivedDelegations(); + break; + } + setDelegations(response); + setIsLoading(false); + } catch (err) { + console.warn('Failed to get delegations', err); + setIsLoading(false); } + }; + const _handleOnUserPress = (username: string) => { + navigation.navigate({ + name: ROUTES.SCREENS.PROFILE, + params: { + username, + }, + key: username, + }); + setShowModal(false); + }; - const _getDelegations = async () => { - - try { - setIsLoading(true); - let response: DelegationItem[] = []; - switch (mode) { - case MODES.DELEGATEED: - response = await _getVestingDelegations(); - break; - case MODES.RECEIVED: - response = await _getReceivedDelegations(); - break; - } - setDelegations(response); - setIsLoading(false); - } catch (err) { - console.warn("Failed to get delegations", err) - setIsLoading(false); - } - + const _handleOnPressUpdate = (username: string) => { + if (mode === MODES.DELEGATEED) { + console.log('delegate HP!'); + navigation.navigate({ + name: ROUTES.SCREENS.TRANSFER, + params: { + transferType: 'delegate', + fundType: 'HIVE_POWER', + referredUsername: username, + }, + }); + setShowModal(false); } + }; + const title = intl.formatMessage({ id: `wallet.${mode}` }); - const _handleOnUserPress = (username:string) => { - navigation.navigate({ - name: ROUTES.SCREENS.PROFILE, - params: { - username, - }, - key: username - }); - setShowModal(false); - }; - - const _handleOnPressUpdate = (username:string) => { - if(mode === MODES.DELEGATEED){ - console.log('delegate HP!'); - navigation.navigate({ - name: ROUTES.SCREENS.TRANSFER, - params: { - transferType: 'delegate', - fundType: 'HIVE_POWER', - referredUsername: username, - }, - }); - setShowModal(false); - } - } - - 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 timeString = new Date(item.timestamp).toDateString(); - const subRightText = mode === MODES.DELEGATEED && intl.formatMessage({id:"wallet.tap_update"}) - - return ( - _handleOnUserPress(item.username)} - onPressRightText={()=>_handleOnPressUpdate(item.username)} - isClickable - /> - ); - } - - - - const _renderContent = () => { - return ( - - {({ data, filterResult, handleSearch }) => ( - <> - { setShowModal(false) }} - title={`${title} (${data && data.length})`} - isHasSearch - handleOnSearch={(text) => handleSearch(text, 'username')} - /> - item.delegator} - removeClippedSubviews={false} - renderItem={_renderItem} - refreshControl={ - - } - /> - - )} - - - ) - } + const _renderItem = ({ item, index }: { item: DelegationItem; index: number }) => { + 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' }); return ( - setShowModal(false)} - isFullScreen - isCloseButton - presentationStyle="formSheet" - animationType="slide" - style={styles.delegationsModal} - > - {_renderContent()} - - ) -}) \ No newline at end of file + _handleOnUserPress(item.username)} + onPressRightText={() => _handleOnPressUpdate(item.username)} + isClickable + /> + ); + }; + + const _renderContent = () => { + return ( + + {({ data, filterResult, handleSearch }) => ( + <> + { + setShowModal(false); + }} + title={`${title} (${data && data.length})`} + isHasSearch + handleOnSearch={(text) => handleSearch(text, 'username')} + /> + item.delegator} + removeClippedSubviews={false} + renderItem={_renderItem} + refreshControl={ + + } + /> + + )} + + ); + }; + + return ( + setShowModal(false)} + isFullScreen + isCloseButton + presentationStyle="formSheet" + animationType="slide" + style={styles.delegationsModal} + > + {_renderContent()} + + ); +}); diff --git a/src/screens/coinDetails/children/index.ts b/src/screens/coinDetails/children/index.ts index 055ec0d6d..9a719a2b1 100644 --- a/src/screens/coinDetails/children/index.ts +++ b/src/screens/coinDetails/children/index.ts @@ -1,6 +1,6 @@ export * from './coinBasics'; export * from './coinChart'; -export * from './rangeSelector'; +export * from './rangeSelector'; export * from './coinSummary'; export * from './activitiesList'; -export * from './coinActions'; \ No newline at end of file +export * from './coinActions'; diff --git a/src/screens/coinDetails/children/rangeSelector.tsx b/src/screens/coinDetails/children/rangeSelector.tsx index ea8d0d5b1..c824eeb7f 100644 --- a/src/screens/coinDetails/children/rangeSelector.tsx +++ b/src/screens/coinDetails/children/rangeSelector.tsx @@ -1,75 +1,70 @@ -import React, { useState } from 'react' -import { View, Text } from 'react-native' -import EStyleSheet from 'react-native-extended-stylesheet' -import { TouchableOpacity } from 'react-native-gesture-handler' -import styles from './children.styles' +import React, { useState } from 'react'; +import { View, Text } from 'react-native'; +import EStyleSheet from 'react-native-extended-stylesheet'; +import { TouchableOpacity } from 'react-native-gesture-handler'; +import styles from './children.styles'; interface RangeOption { - label:string; - value:number; + label: string; + value: number; } interface RangeSelectorProps { - range:number; - onRangeChange:(range:number)=>void; + range: number; + onRangeChange: (range: number) => void; } -export const RangeSelector = ({range, onRangeChange}:RangeSelectorProps) => { +export const RangeSelector = ({ range, onRangeChange }: RangeSelectorProps) => { + const _onSelection = (range: number) => { + console.log('selection', range); + onRangeChange(range); + //TODO: implement on range change prop + }; - const _onSelection = (range:number) => { - console.log('selection', range) - onRangeChange(range); - //TODO: implement on range change prop - } + const _renderRangeButtons = FILTERS.map((item: RangeOption) => ( + _onSelection(item.value)}> + + + {item.label} + + + + )); - const _renderRangeButtons = FILTERS.map((item:RangeOption)=>( - _onSelection(item.value)} > - - - {item.label} - - - - )) - - return ( - - {_renderRangeButtons} - - ) -} + return {_renderRangeButtons}; +}; const FILTERS = [ - { - label:'24H', - value:1 - }, - { - label:'1W', - value:7 - }, - { - label:'1M', - value:20 - }, - { - label:'1Y', - value:365 - }, - { - label:'5Y', - value:365*5 - }, -] as RangeOption[] + { + label: '24H', + value: 1, + }, + { + label: '1W', + value: 7, + }, + { + label: '1M', + value: 20, + }, + { + label: '1Y', + value: 365, + }, + { + label: '5Y', + value: 365 * 5, + }, +] as RangeOption[]; diff --git a/src/screens/coinDetails/screen/coinDetailsScreen.tsx b/src/screens/coinDetails/screen/coinDetailsScreen.tsx index 79b10419f..b1208eb63 100644 --- a/src/screens/coinDetails/screen/coinDetailsScreen.tsx +++ b/src/screens/coinDetails/screen/coinDetailsScreen.tsx @@ -1,17 +1,17 @@ -import { View, Alert, AppState, AppStateStatus } from 'react-native' -import React, { useEffect, useRef, useState } from 'react' -import { BasicHeader } from '../../../components' -import { CoinSummary } from '../children' +import { View, Alert, AppState, AppStateStatus } from 'react-native'; +import React, { useEffect, useRef, useState } from 'react'; +import { useIntl } from 'react-intl'; +import { BasicHeader } from '../../../components'; +import { CoinSummary } from '../children'; import styles from './screen.styles'; -import ActivitiesList from '../children/activitiesList' -import { useAppDispatch, useAppSelector } from '../../../hooks' +import ActivitiesList from '../children/activitiesList'; +import { useAppDispatch, useAppSelector } from '../../../hooks'; import { CoinActivitiesCollection, QuoteItem } from '../../../redux/reducers/walletReducer'; import { fetchCoinActivities } from '../../../utils/wallet'; import { fetchAndSetCoinsData, setCoinActivities } from '../../../redux/actions/walletActions'; import { navigate } from '../../../navigation/service'; import ROUTES from '../../../constants/routeNames'; import { COIN_IDS } from '../../../constants/defaultCoins'; -import { useIntl } from 'react-intl'; import { DelegationsModal, MODES } from '../children/delegationsModal'; export interface CoinDetailsScreenParams { @@ -19,8 +19,8 @@ export interface CoinDetailsScreenParams { } interface CoinDetailsScreenProps { - navigation: any - route: any + navigation: any; + route: any; } const FETCH_ITEMS_LIMIT = 500; @@ -31,7 +31,7 @@ const CoinDetailsScreen = ({ navigation, route }: CoinDetailsScreenProps) => { const coinId = route.params?.coinId; if (!coinId) { - throw new Error("Coin symbol must be passed") + throw new Error('Coin symbol must be passed'); } //refs @@ -39,13 +39,17 @@ const CoinDetailsScreen = ({ navigation, route }: CoinDetailsScreenProps) => { const delegationsModalRef = useRef(null); //redux props - const currentAccount = useAppSelector(state => state.account.currentAccount); - const globalProps = useAppSelector(state => state.account.globalProps); - const selectedCoins = useAppSelector(state => state.wallet.selectedCoins); - const coinData: CoinData = useAppSelector(state => state.wallet.coinsData[coinId]); - const quote: QuoteItem = useAppSelector(state => state.wallet.quotes ? state.wallet.quotes[coinId] : {}); - const coinActivities: CoinActivitiesCollection = useAppSelector(state => state.wallet.coinsActivities[coinId]); - const isPinCodeOpen = useAppSelector(state => state.application.isPinCodeOpen); + const currentAccount = useAppSelector((state) => state.account.currentAccount); + const globalProps = useAppSelector((state) => state.account.globalProps); + const selectedCoins = useAppSelector((state) => state.wallet.selectedCoins); + const coinData: CoinData = useAppSelector((state) => state.wallet.coinsData[coinId]); + const quote: QuoteItem = useAppSelector((state) => + state.wallet.quotes ? state.wallet.quotes[coinId] : {}, + ); + const coinActivities: CoinActivitiesCollection = useAppSelector( + (state) => state.wallet.coinsActivities[coinId], + ); + const isPinCodeOpen = useAppSelector((state) => state.application.isPinCodeOpen); //state const [symbol] = useState(selectedCoins.find((item) => item.id === coinId).symbol); @@ -59,65 +63,73 @@ const CoinDetailsScreen = ({ navigation, route }: CoinDetailsScreenProps) => { _fetchDetails(true); AppState.addEventListener('change', _handleAppStateChange); return _cleanup; - }, []) - + }, []); const _cleanup = () => { AppState.removeEventListener('change', _handleAppStateChange); - } - + }; const _handleAppStateChange = (nextAppState: AppStateStatus) => { if (appState.current.match(/inactive|background/) && nextAppState === 'active') { - console.log("updating coins activities on app resume", coinId) + console.log('updating coins activities on app resume', coinId); _fetchDetails(true); } appState.current = nextAppState; - } - + }; const _fetchDetails = async (refresh = false) => { - if (refresh) { setRefreshing(refresh); dispatch(fetchAndSetCoinsData(refresh)); - } else if(noMoreActivities || loading) { - console.log('Skipping transaction fetch', completedActivities.lastItem?.trxIndex) + } else if (noMoreActivities || loading) { + console.log('Skipping transaction fetch', completedActivities.lastItem?.trxIndex); return; } setLoading(true); - const startAt = refresh || !completedActivities.length ? -1 : completedActivities.lastItem?.trxIndex - 1; - const _activites = await fetchCoinActivities(currentAccount.name, coinId, symbol, globalProps, startAt, FETCH_ITEMS_LIMIT); + const startAt = + refresh || !completedActivities.length ? -1 : completedActivities.lastItem?.trxIndex - 1; + const _activites = await fetchCoinActivities( + currentAccount.name, + coinId, + symbol, + globalProps, + startAt, + FETCH_ITEMS_LIMIT, + ); - if(refresh){ + if (refresh) { dispatch(setCoinActivities(coinId, _activites)); } - - setCompletedActivities(refresh ? _activites.completed : [...completedActivities, ..._activites.completed]); - setNoMoreActivities(!_activites.completed.length || _activites.completed.lastItem.trxIndex < FETCH_ITEMS_LIMIT); + + setCompletedActivities( + refresh ? _activites.completed : [...completedActivities, ..._activites.completed], + ); + setNoMoreActivities( + !_activites.completed.length || _activites.completed.lastItem.trxIndex < FETCH_ITEMS_LIMIT, + ); setRefreshing(false); setLoading(false); - } - + }; if (!coinData) { - Alert.alert("Invalid coin data"); + Alert.alert('Invalid coin data'); navigation.goBack(); } - const _onInfoPress = (dataKey:string) => { - if((dataKey === MODES.DELEGATEED || dataKey === MODES.RECEIVED) && delegationsModalRef.current) { - delegationsModalRef.current.showModal(dataKey) + const _onInfoPress = (dataKey: string) => { + if ( + (dataKey === MODES.DELEGATEED || dataKey === MODES.RECEIVED) && + delegationsModalRef.current + ) { + delegationsModalRef.current.showModal(dataKey); } - } - + }; const _onActionPress = (transferType: string) => { - - let navigateTo = ROUTES.SCREENS.TRANSFER + let navigateTo = ROUTES.SCREENS.TRANSFER; let navigateParams = {}; if (coinId === COIN_IDS.ECENCY && transferType !== 'dropdown_transfer') { @@ -125,38 +137,38 @@ const CoinDetailsScreen = ({ navigation, route }: CoinDetailsScreenProps) => { navigateParams = { balance: coinData.balance, redeemType: transferType === 'dropdown_promote' ? 'promote' : 'boost', - } + }; } else { - const balance = transferType === 'withdraw_hive' || transferType === 'withdraw_hbd' - ? coinData.savings : coinData.balance; + const balance = + transferType === 'withdraw_hive' || transferType === 'withdraw_hbd' + ? coinData.savings + : coinData.balance; navigateParams = { transferType: coinId === COIN_IDS.ECENCY ? 'points' : transferType, fundType: coinId === COIN_IDS.ECENCY ? 'ESTM' : symbol, - balance + balance, }; } if (isPinCodeOpen) { navigate({ routeName: ROUTES.SCREENS.PINCODE, - params:{ + params: { navigateTo, navigateParams, - } - }) + }, + }); } else { navigate({ routeName: navigateTo, - params: navigateParams + params: navigateParams, }); } - } - + }; const _onRefresh = () => { _fetchDetails(true); - } - + }; const _renderHeaderComponent = ( { coinData={coinData} percentChagne={quote.percentChange || 0} onActionPress={_onActionPress} - onInfoPress={_onInfoPress} /> - ) - + onInfoPress={_onInfoPress} + /> + ); return ( @@ -183,7 +195,7 @@ const CoinDetailsScreen = ({ navigation, route }: CoinDetailsScreenProps) => { /> - ) -} + ); +}; -export default CoinDetailsScreen \ No newline at end of file +export default CoinDetailsScreen; diff --git a/src/screens/coinDetails/screen/screen.styles.ts b/src/screens/coinDetails/screen/screen.styles.ts index 12ddacb38..200facecd 100644 --- a/src/screens/coinDetails/screen/screen.styles.ts +++ b/src/screens/coinDetails/screen/screen.styles.ts @@ -2,9 +2,7 @@ import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ container: { - flex:1, + flex: 1, backgroundColor: '$primaryBackgroundColor', }, - - }); diff --git a/src/screens/editHistoryScreen/editHistoryScreen.tsx b/src/screens/editHistoryScreen/editHistoryScreen.tsx index a39710ace..70400faa2 100644 --- a/src/screens/editHistoryScreen/editHistoryScreen.tsx +++ b/src/screens/editHistoryScreen/editHistoryScreen.tsx @@ -1,23 +1,15 @@ -import React, { Fragment } from 'react'; -import { useEffect, useState } from 'react'; +import React, { Fragment, useEffect, useState } from 'react'; + import { useIntl } from 'react-intl'; -import { - Alert, - - FlatList, - ScrollView, - Text, - TouchableOpacity, - View, -} from 'react-native'; +import { Alert, FlatList, ScrollView, Text, TouchableOpacity, View } from 'react-native'; +import EStyleSheet from 'react-native-extended-stylesheet'; +import AutoHeightWebView from 'react-native-autoheight-webview'; import { BasicHeader, Icon, PostPlaceHolder, TextInput } from '../../components'; // styles -import EStyleSheet from 'react-native-extended-stylesheet'; import styles from './editHistoryScreenStyles'; import { getCommentHistory } from '../../providers/ecency/ecency'; import { dateToFormatted } from '../../utils/time'; -import AutoHeightWebView from 'react-native-autoheight-webview'; import historyBuilder from './historyBuilder'; import getWindowDimensions from '../../utils/getWindowDimensions'; @@ -84,14 +76,9 @@ const EditHistoryScreen = ({ route }) => { } `; - const diffIconStyle = - { - color: showDiff - ? EStyleSheet.value('$primaryBlue') - : EStyleSheet.value('$iconColor'), - } - ; - + const diffIconStyle = { + color: showDiff ? EStyleSheet.value('$primaryBlue') : EStyleSheet.value('$iconColor'), + }; useEffect(() => { _getCommentHistory(); }, []); @@ -108,7 +95,6 @@ const EditHistoryScreen = ({ route }) => { setIsLoading(false); }; - const _renderVersionsListItem = ({ item, index, @@ -140,7 +126,6 @@ const EditHistoryScreen = ({ route }) => { ); }; - const _renderVersionsList = () => ( { - + @@ -168,7 +153,6 @@ const EditHistoryScreen = ({ route }) => { ); }; - const _renderPlainBody = (selectedItem: CommentHistoryListItemDiff) => { return ( <> @@ -180,7 +164,7 @@ const EditHistoryScreen = ({ route }) => { editable={false} /> - + {selectedItem.tags} @@ -196,7 +180,6 @@ const EditHistoryScreen = ({ route }) => { ); }; - const _renderBody = () => { const selectedItem = editHistory.find((x) => x.v === versionSelected); if (!selectedItem) { diff --git a/src/screens/editHistoryScreen/editHistoryScreenStyles.ts b/src/screens/editHistoryScreen/editHistoryScreenStyles.ts index ee5248230..64343491b 100644 --- a/src/screens/editHistoryScreen/editHistoryScreenStyles.ts +++ b/src/screens/editHistoryScreen/editHistoryScreenStyles.ts @@ -1,8 +1,8 @@ import EStyleSheet from 'react-native-extended-stylesheet'; export default EStyleSheet.create({ - mainContainer:{ - flex:1, + mainContainer: { + flex: 1, backgroundColor: '$primaryBackgroundColor', }, versionsListContainer: { @@ -10,7 +10,7 @@ export default EStyleSheet.create({ paddingTop: 16, }, versionsListContentContainer: { - paddingHorizontal: 16 + paddingHorizontal: 16, }, versionItemBtn: { // backgroundColor: '$primaryBlue', @@ -25,7 +25,7 @@ export default EStyleSheet.create({ versionItemBtnText: { color: '$pureWhite', fontSize: 14, - fontWeight: '700' + fontWeight: '700', }, versionItemBtnDate: { color: '$black', @@ -34,9 +34,7 @@ export default EStyleSheet.create({ previewScrollContentContainer: { paddingHorizontal: 16, }, - postHeaderContainer: { - - }, + postHeaderContainer: {}, postHeaderTitle: { fontSize: 24, color: '$primaryBlack', @@ -44,7 +42,7 @@ export default EStyleSheet.create({ fontFamily: '$primaryFont', marginBottom: 11, }, - postBodyText:{ + postBodyText: { fontSize: 16, color: '$primaryBlack', fontFamily: '$primaryFont', diff --git a/src/screens/editHistoryScreen/historyBuilder.tsx b/src/screens/editHistoryScreen/historyBuilder.tsx index 2dcf43bcc..068d9e377 100644 --- a/src/screens/editHistoryScreen/historyBuilder.tsx +++ b/src/screens/editHistoryScreen/historyBuilder.tsx @@ -1,5 +1,5 @@ -import { CommentHistoryItem } from '../../providers/ecency/ecency.types'; import { diff_match_patch } from 'diff-match-patch'; +import { CommentHistoryItem } from '../../providers/ecency/ecency.types'; const dmp = new diff_match_patch(); diff --git a/src/screens/editor/children/postOptionsModalStyles.ts b/src/screens/editor/children/postOptionsModalStyles.ts index f6146c230..f1bcc1801 100644 --- a/src/screens/editor/children/postOptionsModalStyles.ts +++ b/src/screens/editor/children/postOptionsModalStyles.ts @@ -1,110 +1,109 @@ -import { TextStyle, StyleSheet, ViewStyle, ImageStyle } from 'react-native'; +import { TextStyle, StyleSheet, ViewStyle, ImageStyle } from 'react-native'; import EStyleSheet from 'react-native-extended-stylesheet'; import getWindowDimensions from '../../../utils/getWindowDimensions'; -const gridItemWidth = ((getWindowDimensions().width/2) - 32); -const gridItemHeight = (gridItemWidth * 500)/600 +const gridItemWidth = getWindowDimensions().width / 2 - 32; +const gridItemHeight = (gridItemWidth * 500) / 600; export default EStyleSheet.create({ - modalStyle: { - flex: 1, - backgroundColor: '$primaryBackgroundColor', - margin: 0, - paddingTop: 32, - paddingBottom: 16, - }, - fillSpace:{ - flex:1 - }, - container: { - paddingVertical: 8, - paddingHorizontal: 32, - }, - bodyWrapper: { - flex: 3, - paddingHorizontal:16 - }, - floatingContainer:{ - position:'absolute', - bottom:0, - right:20, - justifyContent:'flex-end', - zIndex:10 - } as ViewStyle, + modalStyle: { + flex: 1, + backgroundColor: '$primaryBackgroundColor', + margin: 0, + paddingTop: 32, + paddingBottom: 16, + }, + fillSpace: { + flex: 1, + }, + container: { + paddingVertical: 8, + paddingHorizontal: 32, + }, + bodyWrapper: { + flex: 3, + paddingHorizontal: 16, + }, + floatingContainer: { + position: 'absolute', + bottom: 0, + right: 20, + justifyContent: 'flex-end', + zIndex: 10, + } as ViewStyle, - mediaItem:{ - margin:8, - height:gridItemHeight, - width:gridItemWidth, - borderRadius:16, - backgroundColor:'$primaryLightGray' - } as ImageStyle, - - 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, - dateTimeModa:{ - backgroundColor: 'white', - alignItems: 'center', - } as ViewStyle, - title: { - fontWeight: '700', - flex:1, - fontSize:16, - color:'$primaryBlack' - } as TextStyle, + mediaItem: { + margin: 8, + height: gridItemHeight, + width: gridItemWidth, + borderRadius: 16, + backgroundColor: '$primaryLightGray', + } as ImageStyle, - btnText:{ - color:'$pureWhite' - } as TextStyle, - saveButton:{ - width:150, - paddingVertical:16, - borderRadius:32, - marginVertical:16, - marginRight:32, - justifyContent:'center', - alignItems:'center', - alignSelf:'flex-end' - } 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, + 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, + dateTimeModa: { + backgroundColor: 'white', + alignItems: 'center', + } as ViewStyle, + title: { + fontWeight: '700', + flex: 1, + fontSize: 16, + color: '$primaryBlack', + } as TextStyle, - itemIcon:{ - color:'$white', - } as ViewStyle, + btnText: { + color: '$pureWhite', + } as TextStyle, + saveButton: { + width: 150, + paddingVertical: 16, + borderRadius: 32, + marginVertical: 16, + marginRight: 32, + justifyContent: 'center', + alignItems: 'center', + alignSelf: 'flex-end', + } 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, - itemIconWrapper:{ - justifyContent:'center', - alignItems:'center', - backgroundColor:'$primaryRed', + itemIcon: { + color: '$white', + } as ViewStyle, - } as ViewStyle, + itemIconWrapper: { + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '$primaryRed', + } as ViewStyle, - removeItemContainer:{ - position:'absolute', - top:16, - right:16 - } as ViewStyle -}) + removeItemContainer: { + position: 'absolute', + top: 16, + right: 16, + } as ViewStyle, +}); diff --git a/src/screens/editor/container/editorContainer.tsx b/src/screens/editor/container/editorContainer.tsx index 2f57ed3ff..70fd0dbab 100644 --- a/src/screens/editor/container/editorContainer.tsx +++ b/src/screens/editor/container/editorContainer.tsx @@ -55,7 +55,6 @@ import { PointActivityIds } from '../../../providers/ecency/ecency.types'; * */ - class EditorContainer extends Component { _isMounted = false; _updatedDraftFields = null; @@ -549,7 +548,7 @@ class EditorContainer extends Component { intl, navigation, pinCode, - userActivityMutation + userActivityMutation, // isDefaultFooter, } = this.props; const { rewardType, isPostSending, thumbUrl, draftId, shouldReblog } = this.state; @@ -621,9 +620,9 @@ class EditorContainer extends Component { console.log(response); // track user activity for points userActivityMutation.mutate({ - pointsTy:PointActivityIds.POST, - transactionId:response.id - }) + pointsTy: PointActivityIds.POST, + transactionId: response.id, + }); //reblog if flag is active if (shouldReblog) { @@ -631,9 +630,9 @@ class EditorContainer extends Component { .then((resp) => { //track user activity for points on reblog userActivityMutation.mutate({ - pointsTy:PointActivityIds.REBLOG, - transactionId:resp.id - }) + pointsTy: PointActivityIds.REBLOG, + transactionId: resp.id, + }); console.log('Successfully reblogged post', resp); }) .catch((err) => { @@ -710,9 +709,9 @@ class EditorContainer extends Component { .then((response) => { //record user activity for points userActivityMutation.mutate({ - pointsTy:PointActivityIds.COMMENT, - transactionId:response.id - }) + pointsTy: PointActivityIds.COMMENT, + transactionId: response.id, + }); AsyncStorage.setItem('temp-reply', ''); this._handleSubmitSuccess(); @@ -1150,9 +1149,9 @@ const mapStateToProps = (state) => ({ }); const mapQueriesToProps = () => ({ - queryClient:useQueryClient(), - userActivityMutation:useUserActivityMutation() -}) + queryClient: useQueryClient(), + userActivityMutation: useUserActivityMutation(), +}); export default connect(mapStateToProps)( injectIntl((props) => ), diff --git a/src/screens/feed/screen/feedScreen.tsx b/src/screens/feed/screen/feedScreen.tsx index c866fcf6e..66860c3be 100644 --- a/src/screens/feed/screen/feedScreen.tsx +++ b/src/screens/feed/screen/feedScreen.tsx @@ -11,28 +11,25 @@ import { AccountContainer } from '../../../containers'; // Styles import styles from './feedStyles'; -import { - getDefaultFilters, getFilterMap, -} from '../../../constants/options/filters'; +import { getDefaultFilters, getFilterMap } from '../../../constants/options/filters'; import { useAppSelector } from '../../../hooks'; const FeedScreen = () => { - - const mainTabs = useAppSelector((state) => state.customTabs.mainTabs || getDefaultFilters('main')); + const mainTabs = useAppSelector( + (state) => state.customTabs.mainTabs || getDefaultFilters('main'), + ); const filterOptions = mainTabs.map((key) => getFilterMap('main')[key]); const [lazyLoad, setLazyLoad] = useState(false); - - const _lazyLoadContent = () => { - if(!lazyLoad){ + if (!lazyLoad) { setTimeout(() => { setLazyLoad(true); - }, 100) + }, 100); } - } + }; return ( @@ -40,7 +37,6 @@ const FeedScreen = () => {
- {lazyLoad && ( { selectedOptionIndex={get(currentAccount, 'name', null) ? 0 : 2} feedUsername={get(currentAccount, 'name', null)} isFeedScreen={true} - pageType='main' + pageType="main" /> - )} - )} diff --git a/src/screens/login/container/loginContainer.tsx b/src/screens/login/container/loginContainer.tsx index 3835021e5..808f17e3f 100644 --- a/src/screens/login/container/loginContainer.tsx +++ b/src/screens/login/container/loginContainer.tsx @@ -168,7 +168,7 @@ class LoginContainer extends PureComponent { dispatch(setFeedPosts([])); //track user activity for login - userActivityMutation.mutate({ pointsTy:PointActivityIds.LOGIN }) + userActivityMutation.mutate({ pointsTy: PointActivityIds.LOGIN }); setExistUser(true); this._setPushToken(result.name); const encryptedPin = encryptKey(Config.DEFAULT_PIN, Config.PIN_KEY); @@ -193,8 +193,8 @@ class LoginContainer extends PureComponent { const errorDescription = err?.response?.data?.error_description ? err?.response?.data?.error_description : intl.formatMessage({ - id: err.message, - }); + id: err.message, + }); Alert.alert( intl.formatMessage({ id: 'login.login_failed', @@ -291,9 +291,9 @@ const mapStateToProps = (state) => ({ }); const mapQueriesToProps = () => ({ - userActivityMutation: useUserActivityMutation() -}) + userActivityMutation: useUserActivityMutation(), +}); -export default connect(mapStateToProps)(injectIntl((props) => ( - -))); +export default connect(mapStateToProps)( + injectIntl((props) => ), +); diff --git a/src/screens/pinCode/children/pinCodeView.tsx b/src/screens/pinCode/children/pinCodeView.tsx index cb4752069..719ee9731 100644 --- a/src/screens/pinCode/children/pinCodeView.tsx +++ b/src/screens/pinCode/children/pinCodeView.tsx @@ -5,115 +5,114 @@ import { useIntl } from 'react-intl'; import { Text, TouchableOpacity, View } from 'react-native'; import { IconButton, NumericKeyboard, PinAnimatedInput, UserAvatar } from '../../../components'; -import styles from '../children/pinCodeStyles'; +import styles from './pinCodeStyles'; -const PinCodeView = forwardRef(({ - informationText, - showForgotButton, - username, - handleForgotButton, - setPinCode, - hideCloseButton -}, ref) => { - const [pin, setPin] = useState(''); - const [loading, setLoading] = useState(false); - const intl = useIntl(); - const navigation = useNavigation(); +const PinCodeView = forwardRef( + ( + { + informationText, + showForgotButton, + username, + handleForgotButton, + setPinCode, + hideCloseButton, + }, + ref, + ) => { + const [pin, setPin] = useState(''); + const [loading, setLoading] = useState(false); + const intl = useIntl(); + const navigation = useNavigation(); - useImperativeHandle(ref, () => ({ - setPinThroughBiometric(bioPin) { - if (bioPin && bioPin.length === 4) { + useImperativeHandle(ref, () => ({ + setPinThroughBiometric(bioPin) { + if (bioPin && bioPin.length === 4) { + setLoading(true); + setPin(bioPin); + } + }, + })); + + useEffect(() => { + _handlePinComplete(); + }, [pin]); + + const _handlePinComplete = async () => { + if (pin.length === 4) { setLoading(true); - setPin(bioPin) - } - } - })); - - - - useEffect(() => { - _handlePinComplete(); - }, [pin]); - - - - const _handlePinComplete = async () => { - if (pin.length === 4) { - setLoading(true); - await setPinCode(pin); - setPin(''); - setLoading(false); - } - }; - - - const _handleKeyboardOnPress = async (value) => { - try { - if (loading) { - return; - } - if (value === 'clear') { + await setPinCode(pin); setPin(''); - return; + setLoading(false); } - const newPin = `${pin}${value}`; + }; - if (pin.length < 4) { - setPin(newPin); - } else if (pin.length >= 4) { - setPin(`${value}`); + const _handleKeyboardOnPress = async (value) => { + try { + if (loading) { + return; + } + if (value === 'clear') { + setPin(''); + return; + } + const newPin = `${pin}${value}`; + + if (pin.length < 4) { + setPin(newPin); + } else if (pin.length >= 4) { + setPin(`${value}`); + } + } catch (err) { + console.warn('Failed to handle keyboard press as expected', err); } - } catch (err) { - console.warn('Failed to handle keyboard press as expected', err); - } - }; + }; - const _handleBackPress = () => { - navigation.goBack(); - } + const _handleBackPress = () => { + navigation.goBack(); + }; - return ( + return ( + + {!hideCloseButton && ( + + + + )} - - {!hideCloseButton && - - } - - - + + + + + {`@${username}`} + + + {informationText} + + + + + + + + {showForgotButton ? ( + handleForgotButton()} style={styles.forgotButtonView}> + + {intl.formatMessage({ + id: 'pincode.forgot_text', + })} + + + ) : ( + + )} - - {`@${username}`} - - - {informationText} - - - - - - - - {showForgotButton ? ( - handleForgotButton()} style={styles.forgotButtonView}> - - {intl.formatMessage({ - id: 'pincode.forgot_text', - })} - - - ) : ( - - )} - - - - ); -}) + ); + }, +); export default PinCodeView; diff --git a/src/screens/pinCode/container/pinCodeContainer.tsx b/src/screens/pinCode/container/pinCodeContainer.tsx index a80356628..e244d066e 100644 --- a/src/screens/pinCode/container/pinCodeContainer.tsx +++ b/src/screens/pinCode/container/pinCodeContainer.tsx @@ -6,12 +6,10 @@ import Config from 'react-native-config'; import get from 'lodash/get'; import FingerprintScanner from 'react-native-fingerprint-scanner'; - // Actions & Services +import { withNavigation } from '@react-navigation/compat'; import { navigate } from '../../../navigation/service'; -import { - updatePinCode, -} from '../../../providers/hive/auth'; +import { updatePinCode } from '../../../providers/hive/auth'; import { isPinCodeOpen, isRenderRequired, @@ -33,14 +31,11 @@ import { encryptKey, decryptKey } from '../../../utils/crypto'; import MigrationHelpers from '../../../utils/migrationHelpers'; // Component -import { withNavigation } from '@react-navigation/compat'; import PinCodeView from '../children/pinCodeView'; - class PinCodeContainer extends Component { screenRef = null; - constructor(props) { super(props); @@ -54,10 +49,8 @@ class PinCodeContainer extends Component { }; } - //sets initial pin code screen label based on oldPinVerified param/state componentDidMount() { - const { intl } = this.props; const { isOldPinVerified } = this.state; @@ -134,7 +127,6 @@ class PinCodeContainer extends Component { } }; - //routine for checking and setting new pin code, same routine is used for //setting pin for the first time _resetPinCode = (pin) => @@ -148,12 +140,10 @@ class PinCodeContainer extends Component { } = this.props; const { isOldPinVerified, oldPinCode, newPinCode } = this.state; - //if old pin already verified, check new pin setup conditions. if (isOldPinVerified) { //if newPin already exist and pin is a valid pin, compare and set new pin if (pin !== undefined && pin === newPinCode) { - this._savePinCode(pin); if (callback) { callback(pin, oldPinCode); @@ -198,8 +188,7 @@ class PinCodeContainer extends Component { // if old pin code is not yet verified attempt to verify code else { - - let unlockPin = decryptKey(encUnlockPin, Config.PIN_KEY) + let unlockPin = decryptKey(encUnlockPin, Config.PIN_KEY); //check if pins match if (unlockPin !== pin) { @@ -208,7 +197,6 @@ class PinCodeContainer extends Component { return; } - this.setState({ isOldPinVerified: true }); this.setState({ informationText: intl.formatMessage({ @@ -218,12 +206,9 @@ class PinCodeContainer extends Component { oldPinCode: pin, }); resolve(); - } }); - - _onRefreshTokenFailed = (error) => { setTimeout(() => { const { dispatch, intl } = this.props; @@ -241,8 +226,6 @@ class PinCodeContainer extends Component { }, 300); }; - - //verifies is the pin entered is right or wrong, also migrates to newer locking method _verifyPinCode = async (pin) => { try { @@ -253,27 +236,33 @@ class PinCodeContainer extends Component { encUnlockPin, applicationPinCode, pinCodeParams: { navigateTo, navigateParams, callback }, - navigation + navigation, } = this.props; const { oldPinCode } = this.state; - let unlockPin = encUnlockPin ? - decryptKey(encUnlockPin, Config.PIN_KEY) : decryptKey(applicationPinCode, Config.PIN_KEY); - + let unlockPin = encUnlockPin + ? decryptKey(encUnlockPin, Config.PIN_KEY) + : decryptKey(applicationPinCode, Config.PIN_KEY); //check if pins match if (unlockPin !== pin) { - throw new Error(intl.formatMessage({ - id: 'alert.invalid_pincode', - })); + throw new Error( + intl.formatMessage({ + id: 'alert.invalid_pincode', + }), + ); } //migrate data to default pin if encUnlockPin is not set. if (!encUnlockPin) { - await MigrationHelpers.migrateUserEncryption(dispatch, currentAccount, applicationPinCode, this._onRefreshTokenFailed); + await MigrationHelpers.migrateUserEncryption( + dispatch, + currentAccount, + applicationPinCode, + this._onRefreshTokenFailed, + ); } - //on successful code verification run requested operation passed as props if (callback) { callback(pin, oldPinCode); @@ -287,14 +276,12 @@ class PinCodeContainer extends Component { } else { navigation.goBack(); } - return true; } catch (err) { - throw err + throw err; } - } - + }; //encryptes and saved unlockPin _savePinCode = (pin) => { @@ -303,8 +290,6 @@ class PinCodeContainer extends Component { dispatch(setEncryptedUnlockPin(encryptedPin)); }; - - _forgotPinCode = async () => { const { otherAccounts, dispatch, navigation } = this.props; @@ -320,8 +305,7 @@ class PinCodeContainer extends Component { } dispatch(logoutDone()); dispatch(isPinCodeOpen(false)); - dispatch(isRenderRequired(true)) - + dispatch(isRenderRequired(true)); }) .catch((err) => { console.warn('Failed to remove user data', err); @@ -391,8 +375,7 @@ class PinCodeContainer extends Component { await this._verifyPinCode(pin); } - return true - + return true; } catch (error) { return this._handleFailedAttempt(error); } diff --git a/src/screens/pinCode/screen/pinCodeScreen.tsx b/src/screens/pinCode/screen/pinCodeScreen.tsx index b087e89cf..43bda3ac2 100644 --- a/src/screens/pinCode/screen/pinCodeScreen.tsx +++ b/src/screens/pinCode/screen/pinCodeScreen.tsx @@ -1,36 +1,23 @@ -import React, { useEffect } from 'react' +import React, { useEffect } from 'react'; import { BackHandler } from 'react-native'; import PinCodeContainer from '../container/pinCodeContainer'; - const PinCodeScreen = ({ route, navigation }) => { - - const hideCloseButton = route.params ? - (route.params.hideCloseButton ?? false) : - true; + const hideCloseButton = route.params ? route.params.hideCloseButton ?? false : true; useEffect(() => { - BackHandler.addEventListener('hardwareBackPress', _handleBackPress) - + BackHandler.addEventListener('hardwareBackPress', _handleBackPress); + return _unmount; - }, [navigation]) + }, [navigation]); const _unmount = () => { - BackHandler.removeEventListener('hardwareBackPress', _handleBackPress) - } + BackHandler.removeEventListener('hardwareBackPress', _handleBackPress); + }; - const _handleBackPress = () => hideCloseButton ? true : false; + const _handleBackPress = () => (hideCloseButton ? true : false); + return ; +}; - return ( - - - - - ) -} - -export default PinCodeScreen \ No newline at end of file +export default PinCodeScreen; diff --git a/src/screens/referScreen/referScreen.tsx b/src/screens/referScreen/referScreen.tsx index a0b5e34a7..34b09a566 100644 --- a/src/screens/referScreen/referScreen.tsx +++ b/src/screens/referScreen/referScreen.tsx @@ -1,7 +1,18 @@ -import React, { Fragment } from 'react'; -import { useEffect, useState } from 'react'; +import React, { Fragment, useEffect, useState } from 'react'; + import { useIntl } from 'react-intl'; -import { ActivityIndicator, FlatList, RefreshControl, Share, Text, TouchableOpacity, View } from 'react-native'; +import { + ActivityIndicator, + FlatList, + RefreshControl, + Share, + Text, + TouchableOpacity, + View, +} from 'react-native'; +import get from 'lodash/get'; +import EStyleSheet from 'react-native-extended-stylesheet'; +import { useDispatch } from 'react-redux'; import { BasicHeader, Icon, @@ -10,13 +21,11 @@ import { PopoverWrapper, UserListItem, } from '../../components'; -import get from 'lodash/get'; // utils import { getReferralsList, getReferralsStats } from '../../providers/ecency/ecency'; import { Referral } from '../../models'; // styles -import EStyleSheet from 'react-native-extended-stylesheet'; import styles from './referScreenStyles'; // constants @@ -26,19 +35,18 @@ import ROUTES from '../../constants/routeNames'; import { showProfileModal } from '../../redux/actions/uiAction'; import { navigate } from '../../navigation/service'; import { useAppSelector } from '../../hooks'; -import { useDispatch } from 'react-redux'; const ReferScreen = () => { const intl = useIntl(); const dispatch = useDispatch(); const currentAccount = useAppSelector((state) => state.account.currentAccount); - const isDarkTheme = useAppSelector((state)=>state.application.isDarkTheme) + const isDarkTheme = useAppSelector((state) => state.application.isDarkTheme); const [referralsList, setReferralsList] = useState([]); const [earnedPoints, setEarnedPoint] = useState(0); const [pendingPoints, setPendingPoint] = useState(0); const [loading, setLoading] = useState(true); - const [refreshing, setRefreshing] = useState(false) + const [refreshing, setRefreshing] = useState(false); useEffect(() => { _getReferralsStats(); @@ -47,19 +55,18 @@ const ReferScreen = () => { console.log('-----referralsList----- : ', referralsList); - const _getReferralsList = async (refresh?:boolean) => { - if(refresh){ + const _getReferralsList = async (refresh?: boolean) => { + if (refresh) { setRefreshing(true); } - setLoading(true) + setLoading(true); + + const lastReferralId = + refresh || !referralsList.length ? null : referralsList[referralsList.length - 1]._id; - const lastReferralId = refresh || !referralsList.length - ? null - : referralsList[referralsList.length - 1]._id; - const responseData = await getReferralsList(currentAccount.name, lastReferralId); - setReferralsList(refresh ? responseData : [...referralsList, ...responseData]) + setReferralsList(refresh ? responseData : [...referralsList, ...responseData]); setRefreshing(false); setLoading(false); }; @@ -70,10 +77,10 @@ const ReferScreen = () => { const referralStats = await getReferralsStats(currentAccount.name); const earnedPoints = referralStats.rewarded * 100; const unearnedPoints = (referralStats.total - referralStats.rewarded) * 100; - setEarnedPoint(earnedPoints) - setPendingPoint(unearnedPoints) + setEarnedPoint(earnedPoints); + setPendingPoint(unearnedPoints); setLoading(false); - } + }; const _handleRefer = () => { const shareUrl = `https://ecency.com/signup?referral=${currentAccount.username}`; @@ -94,7 +101,7 @@ const ReferScreen = () => { }); }; - const _handleOnItemPress = (username:string) => { + const _handleOnItemPress = (username: string) => { dispatch(showProfileModal(username)); }; @@ -181,10 +188,10 @@ const ReferScreen = () => { ); const _renderFooterView = ( - - {loading && } + + {loading && } - ) + ); const _renderReferralListItem = ({ item, index }: { item: Referral; index: number }) => { return ( @@ -206,7 +213,7 @@ const ReferScreen = () => { return ( `item ${index}`} removeClippedSubviews={false} ListEmptyComponent={_renderEmptyView} @@ -216,9 +223,9 @@ const ReferScreen = () => { contentContainerStyle={styles.listContentContainer} showsVerticalScrollIndicator={false} onEndReachedThreshold={0.3} - onEndReached={()=>_getReferralsList()} + onEndReached={() => _getReferralsList()} refreshControl={ - _getReferralsList(true)} progressBackgroundColor="#357CE6" @@ -238,9 +245,7 @@ const ReferScreen = () => { id: 'refer.refer_earn', })} /> - - {_renderReferralsList()} - + {_renderReferralsList()} ); }; diff --git a/src/screens/wallet/children/children.styles.ts b/src/screens/wallet/children/children.styles.ts index fb4fc3283..eae85808b 100644 --- a/src/screens/wallet/children/children.styles.ts +++ b/src/screens/wallet/children/children.styles.ts @@ -11,7 +11,7 @@ export default EStyleSheet.create({ borderRadius: 12, overflow: 'hidden', borderWidth: 2, - borderColor: "$primaryLightBackground", + borderColor: '$primaryLightBackground', } as ViewStyle, cardHeader: { @@ -29,19 +29,19 @@ export default EStyleSheet.create({ cardValuesContainer: { marginHorizontal: 8, - justifyContent: 'flex-end' + justifyContent: 'flex-end', } as ViewStyle, claimContainer: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', - marginTop: 8 + marginTop: 8, } as ViewStyle, claimBtn: { flexDirection: 'row', - paddingHorizontal: 16 + paddingHorizontal: 16, } as ViewStyle, claimBtnTitle: { @@ -49,7 +49,7 @@ export default EStyleSheet.create({ fontSize: 14, fontWeight: 'bold', alignSelf: 'center', - textTransform: 'uppercase' + textTransform: 'uppercase', } as TextStyle, claimIconWrapper: { @@ -90,7 +90,7 @@ export default EStyleSheet.create({ left: isRTL() ? 16 : 76, right: isRTL() ? 76 : 16, paddingTop: 8, - flexDirection: isRTL() ? "row-reverse" : "row", + flexDirection: isRTL() ? 'row-reverse' : 'row', justifyContent: 'space-between', borderColor: '$chartText', borderTopWidth: EStyleSheet.hairlineWidth, @@ -127,10 +127,9 @@ export default EStyleSheet.create({ fontSize: 14, color: '$primaryDarkText', fontWeight: '300', - textAlign: 'right' + textAlign: 'right', } as TextStyle, claimActivityIndicator: { - marginLeft: 16 - } as ViewStyle - + marginLeft: 16, + } as ViewStyle, }); diff --git a/src/screens/wallet/children/coinCard.tsx b/src/screens/wallet/children/coinCard.tsx index d462b3bc8..57e8183ac 100644 --- a/src/screens/wallet/children/coinCard.tsx +++ b/src/screens/wallet/children/coinCard.tsx @@ -1,9 +1,9 @@ -import { View, Text, TouchableOpacity, ActivityIndicator } from 'react-native'; +import { View, Text, TouchableOpacity, ActivityIndicator } from 'react-native'; import React, { ComponentType, Fragment, useEffect, useState } from 'react'; -import styles from './children.styles'; -import { Icon, MainButton, SimpleChart } from '../../../components'; import { useIntl } from 'react-intl'; import EStyleSheet from 'react-native-extended-stylesheet'; +import styles from './children.styles'; +import { Icon, MainButton, SimpleChart } from '../../../components'; import getWindowDimensions from '../../../utils/getWindowDimensions'; import { COIN_IDS } from '../../../constants/defaultCoins'; @@ -21,7 +21,7 @@ export interface CoinCardProps { enableBuy?: boolean; isClaiming?: boolean; isLoading?: boolean; - footerComponent: ComponentType + footerComponent: ComponentType; onCardPress: () => void; onClaimPress: () => void; onBoostAccountPress: () => void; @@ -44,9 +44,8 @@ export const CoinCard = ({ isLoading, onCardPress, onClaimPress, - onBoostAccountPress + onBoostAccountPress, }: CoinCardProps) => { - const intl = useIntl(); const [claimExpected, setClaimExpected] = useState(false); @@ -55,35 +54,29 @@ export const CoinCard = ({ if (!isClaiming && claimExpected) { setClaimExpected(false); } - }, [isClaiming]) - + }, [isClaiming]); const _onClaimPress = () => { - setClaimExpected(unclaimedRewards ? true : false) + setClaimExpected(unclaimedRewards ? true : false); onClaimPress(); - } + }; const _renderHeader = ( {/* */} - {symbol} + {symbol} {intl.formatMessage({ id: `wallet.${id}.name` })} - - {`${ownedTokens.toFixed(3)} ${symbol}`} - + {`${ownedTokens.toFixed(3)} ${symbol}`} {`${(ownedTokens * currentValue).toFixed(2)}${currencySymbol}`} - ); - const _renderClaimSection = () => { if (unclaimedRewards || enableBuy) { const btnTitle = unclaimedRewards @@ -91,12 +84,20 @@ export const CoinCard = ({ : intl.formatMessage({ id: `wallet.${id}.buy` }); const _rightComponent = isLoading ? ( - + ) : ( - + - ) + ); return ( @@ -108,16 +109,14 @@ export const CoinCard = ({ onPress={_onClaimPress} > - - {btnTitle} - + {btnTitle} {_rightComponent} - ) + ); } - } + }; const _renderBoostAccount = () => { if (id === COIN_IDS.HP && ownedTokens < 50) { @@ -137,7 +136,7 @@ export const CoinCard = ({ - {intl.formatMessage({ id: `wallet.get_boost` })} + {intl.formatMessage({ id: 'wallet.get_boost' })} {_rightComponent} @@ -145,31 +144,28 @@ export const CoinCard = ({ ); } - } + }; const _renderGraph = () => { const _baseWidth = getWindowDimensions().width - 32; return ( - + - ) - } + ); + }; const _renderFooter = ( {`${currencySymbol} ${currentValue.toFixed(2)}`} - 0 ? styles.textDiffPositive : styles.textDiffNegative}>{`${changePercent >= 0 ? '+' : ''}${changePercent.toFixed(1)}%`} + 0 ? styles.textDiffPositive : styles.textDiffNegative}>{`${ + changePercent >= 0 ? '+' : '' + }${changePercent.toFixed(1)}%`} - ) + ); return ( - + {_renderHeader} {_renderClaimSection()} @@ -178,9 +174,6 @@ export const CoinCard = ({ {!notCrypto ? _renderFooter : } {footerComponent && footerComponent} - - ); }; - diff --git a/src/screens/wallet/children/index.ts b/src/screens/wallet/children/index.ts index dbfc6f6e6..d7065c163 100644 --- a/src/screens/wallet/children/index.ts +++ b/src/screens/wallet/children/index.ts @@ -1 +1 @@ -export * from './coinCard'; \ No newline at end of file +export * from './coinCard'; diff --git a/src/screens/wallet/screen/walletScreen.tsx b/src/screens/wallet/screen/walletScreen.tsx index af255df51..4b6ef65a6 100644 --- a/src/screens/wallet/screen/walletScreen.tsx +++ b/src/screens/wallet/screen/walletScreen.tsx @@ -1,42 +1,49 @@ /* eslint-disable react/jsx-wrap-multilines */ import React, { Fragment, useState, useEffect, useRef } from 'react'; -import { SafeAreaView, View, RefreshControl, Text, Alert, AppState, AppStateStatus } from 'react-native'; +import { + SafeAreaView, + View, + RefreshControl, + Text, + Alert, + AppState, + AppStateStatus, +} from 'react-native'; // Containers import { FlatList } from 'react-native-gesture-handler'; import { useIntl } from 'react-intl'; +import moment from 'moment'; import { LoggedInContainer } from '../../../containers'; // Components -import { - Header, - HorizontalIconList, - PostCardPlaceHolder, -} from '../../../components'; - +import { Header, HorizontalIconList, PostCardPlaceHolder } from '../../../components'; // Styles import globalStyles from '../../../globalStyles'; import styles from './walletScreenStyles'; import { useAppDispatch, useAppSelector } from '../../../hooks'; -import {CoinCard} from '../children'; +import { CoinCard } from '../children'; import { fetchMarketChart, INTERVAL_HOURLY } from '../../../providers/coingecko/coingecko'; import ROUTES from '../../../constants/routeNames'; import { CoinDetailsScreenParams } from '../../coinDetails/screen/coinDetailsScreen'; import POINTS, { POINTS_KEYS } from '../../../constants/options/points'; import { CoinBase, CoinData } from '../../../redux/reducers/walletReducer'; -import { fetchAndSetCoinsData, fetchCoinQuotes, resetWalletData, setPriceHistory } from '../../../redux/actions/walletActions'; +import { + fetchAndSetCoinsData, + fetchCoinQuotes, + resetWalletData, + setPriceHistory, +} from '../../../redux/actions/walletActions'; import { COIN_IDS } from '../../../constants/defaultCoins'; import { claimPoints } from '../../../providers/ecency/ePoint'; import { claimRewardBalance, getAccount } from '../../../providers/hive/dhive'; import { toastNotification } from '../../../redux/actions/uiAction'; -import moment from 'moment'; - const CHART_DAYS_RANGE = 1; -const WalletScreen = ({navigation}) => { +const WalletScreen = ({ navigation }) => { const intl = useIntl(); const dispatch = useAppDispatch(); @@ -45,112 +52,105 @@ const WalletScreen = ({navigation}) => { //redux const isDarkTheme = useAppSelector((state) => state.application.isDarkTheme); - const currency = useAppSelector((state)=>state.application.currency); + const currency = useAppSelector((state) => state.application.currency); - const { - selectedCoins, + const { + selectedCoins, priceHistories, coinsData, updateTimestamp, quotes, ...wallet - } = useAppSelector((state)=>state.wallet); + } = useAppSelector((state) => state.wallet); - const currentAccount = useAppSelector((state)=>state.account.currentAccount); - const pinHash = useAppSelector((state)=>state.application.pin); + const currentAccount = useAppSelector((state) => state.account.currentAccount); + const pinHash = useAppSelector((state) => state.application.pin); //state const [isLoading, setIsLoading] = useState(false); const [refreshing, setRefreshing] = useState(false); const [isClaiming, setIsClaiming] = useState(false); - //side-effects - useEffect(()=>{ + useEffect(() => { AppState.addEventListener('change', _handleAppStateChange); - - //if coinsData is empty, initilise wallet without a fresh acount fetch - _fetchData(Object.keys(coinsData).length?true:false); + //if coinsData is empty, initilise wallet without a fresh acount fetch + _fetchData(Object.keys(coinsData).length ? true : false); return _cleanup; - },[]) + }, []); - useEffect(()=>{ - if(currency.currency !== wallet.vsCurrency || currentAccount.username !== wallet.username ){ + useEffect(() => { + if (currency.currency !== wallet.vsCurrency || currentAccount.username !== wallet.username) { dispatch(resetWalletData()); _fetchData(true); } - },[currency, currentAccount]) - + }, [currency, currentAccount]); const _cleanup = () => { AppState.removeEventListener('change', _handleAppStateChange); - } - + }; //actions - const _handleAppStateChange = (nextAppState:AppStateStatus) => { + const _handleAppStateChange = (nextAppState: AppStateStatus) => { if (appState.current.match(/inactive|background/) && nextAppState === 'active') { - console.log('updating selected coins data on app resume') - _fetchCoinsData(true) + console.log('updating selected coins data on app resume'); + _fetchCoinsData(true); } appState.current = nextAppState; }; - - - const _fetchData = (refresh?:boolean) => { - if(!isLoading){ + const _fetchData = (refresh?: boolean) => { + if (!isLoading) { _fetchPriceHistory(); _fetchCoinsData(refresh); } - } - + }; const _fetchPriceHistory = () => { - selectedCoins.forEach(async (token:CoinBase)=>{ - + selectedCoins.forEach(async (token: CoinBase) => { const expiresAt = priceHistories[token.id]?.expiresAt || 0; const curTime = new Date().getTime(); - - if(!token.notCrypto && curTime > expiresAt ){ - const marketChart = await fetchMarketChart(token.id, currency.currency, CHART_DAYS_RANGE, INTERVAL_HOURLY); - const priceData = marketChart.prices.map(item=>item.yValue); + + if (!token.notCrypto && curTime > expiresAt) { + const marketChart = await fetchMarketChart( + token.id, + currency.currency, + CHART_DAYS_RANGE, + INTERVAL_HOURLY, + ); + const priceData = marketChart.prices.map((item) => item.yValue); dispatch(setPriceHistory(token.id, currency.currency, priceData)); } - - }) - } + }); + }; - - const _fetchCoinsData = async (refresh?:boolean) => { + const _fetchCoinsData = async (refresh?: boolean) => { setIsLoading(true); - if(refresh || !quotes){ + if (refresh || !quotes) { dispatch(fetchCoinQuotes()); } - await dispatch(fetchAndSetCoinsData(refresh)); + await dispatch(fetchAndSetCoinsData(refresh)); setRefreshing(false); setIsLoading(false); - } - + }; const _claimEcencyPoints = async () => { setIsClaiming(true); - try{ - await claimPoints() - await _fetchCoinsData(true); - }catch(error){ + try { + await claimPoints(); + await _fetchCoinsData(true); + } catch (error) { Alert.alert(`${error.message}\nTry again or write to support@ecency.com`); } setIsClaiming(false); }; - const _claimRewardBalance = async () => { setIsClaiming(true); - try{ + try { const account = await getAccount(currentAccount.name); await claimRewardBalance( currentAccount, @@ -158,7 +158,7 @@ const WalletScreen = ({navigation}) => { account.reward_hive_balance, account.reward_hbd_balance, account.reward_vesting_balance, - ) + ); await _fetchCoinsData(true); dispatch( toastNotification( @@ -167,71 +167,63 @@ const WalletScreen = ({navigation}) => { }), ), ); - - }catch(error){ - Alert.alert(intl.formatMessage( - {id:'alert.claim_failed'}, - {message:error.message} - )); + } catch (error) { + Alert.alert(intl.formatMessage({ id: 'alert.claim_failed' }, { message: error.message })); } setIsClaiming(false); - } + }; - - const _claimRewards = (coinId:string) => { - if(isLoading){ + const _claimRewards = (coinId: string) => { + if (isLoading) { setRefreshing(true); - Alert.alert(intl.formatMessage({id:'alert.wallet_updating'}) ); + Alert.alert(intl.formatMessage({ id: 'alert.wallet_updating' })); return; } - switch(coinId){ + switch (coinId) { case COIN_IDS.ECENCY: _claimEcencyPoints(); break; - + case COIN_IDS.HP: - _claimRewardBalance() + _claimRewardBalance(); break; - } - } + }; + const _renderItem = ({ item, index }: { item: CoinBase; index: number }) => { + const coinData: CoinData = coinsData[item.id] || {}; - - const _renderItem = ({ item, index }:{item:CoinBase, index:number}) => { - const coinData:CoinData = coinsData[item.id] || {}; - - const _tokenMarketData:number[] = priceHistories[item.id] ? priceHistories[item.id].data : []; + const _tokenMarketData: number[] = priceHistories[item.id] ? priceHistories[item.id].data : []; const _balance = coinData.balance + (coinData.savings || 0); const quote = quotes ? quotes[item.id] : {}; const _onCardPress = () => { navigation.navigate(ROUTES.SCREENS.COIN_DETAILS, { - coinId:item.id - } as CoinDetailsScreenParams) - } + coinId: item.id, + } as CoinDetailsScreenParams); + }; const _onClaimPress = () => { - if(coinData.unclaimedBalance){ + if (coinData.unclaimedBalance) { _claimRewards(item.id); - } else if(item.id === COIN_IDS.ECENCY) { - navigation.navigate(ROUTES.SCREENS.BOOST) + } else if (item.id === COIN_IDS.ECENCY) { + navigation.navigate(ROUTES.SCREENS.BOOST); } - } - + }; + const _onBoostAccountPress = () => { navigation.navigate({ - name:ROUTES.SCREENS.ACCOUNT_BOOST, - params:{ - username: currentAccount.name - } + name: ROUTES.SCREENS.ACCOUNT_BOOST, + params: { + username: currentAccount.name, + }, }); }; return ( - { onCardPress={_onCardPress} onClaimPress={_onClaimPress} onBoostAccountPress={_onBoostAccountPress} - footerComponent={index === 0 && } - {...item} /> + footerComponent={ + index === 0 && + } + {...item} + /> ); }; @@ -252,19 +247,23 @@ const WalletScreen = ({navigation}) => { return ( - {isLoading - ? intl.formatMessage({id:'wallet.updating'}) - :`${intl.formatMessage({id:'wallet.last_updated'})} ${moment(updateTimestamp).format('HH:mm:ss')}`} + {isLoading + ? intl.formatMessage({ id: 'wallet.updating' }) + : `${intl.formatMessage({ id: 'wallet.last_updated' })} ${moment( + updateTimestamp, + ).format('HH:mm:ss')}`} - ) - } - + ); + }; const _refreshControl = ( {_fetchData(true); setRefreshing(true)}} + onRefresh={() => { + _fetchData(true); + setRefreshing(true); + }} progressBackgroundColor="#357CE6" tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'} titleColor="#fff" @@ -272,7 +271,6 @@ const WalletScreen = ({navigation}) => { /> ); - return (
diff --git a/src/screens/webBrowser/screen/webBrowser.tsx b/src/screens/webBrowser/screen/webBrowser.tsx index 06b625f94..009843784 100644 --- a/src/screens/webBrowser/screen/webBrowser.tsx +++ b/src/screens/webBrowser/screen/webBrowser.tsx @@ -1,56 +1,55 @@ -import React, {useMemo } from 'react'; -import {Alert, StatusBar, View, Text } from 'react-native'; +import React, { useMemo } from 'react'; +import { Alert, StatusBar, View, Text } from 'react-native'; import { WebView } from 'react-native-webview'; import { SafeAreaView } from 'react-native-safe-area-context'; -import {get} from 'lodash'; +import { get } from 'lodash'; import styles from './webBrowserStyles'; import { IconButton } from '../../../components'; export interface WebBrowserParams { - url:string; + url: string; } interface Props { - navigation:{ - goBack:()=>void; - }, - route:{ - params:WebBrowserParams - } + navigation: { + goBack: () => void; + }; + route: { + params: WebBrowserParams; + }; } -const WebBrowser = ({navigation, route}:Props) => { - +const WebBrowser = ({ navigation, route }: Props) => { const url = useMemo(() => route.params?.url, []); - if(!url){ - Alert.alert("DEV: url parameter cannot be empty") + if (!url) { + Alert.alert('DEV: url parameter cannot be empty'); } const _onBackPress = () => { navigation.goBack(); - } + }; const _renderHeader = () => { return ( - - ECENCY - - + + ECENCY + + - ) - } + ); + }; return ( - + {_renderHeader()} { }} /> - ) -} + ); +}; -export default WebBrowser +export default WebBrowser; diff --git a/src/screens/welcome/index.ts b/src/screens/welcome/index.ts index 8fb37e3fe..ae79ddffe 100644 --- a/src/screens/welcome/index.ts +++ b/src/screens/welcome/index.ts @@ -1,3 +1,3 @@ import WelcomeScreen from './screen/WelcomeScreen'; -export default WelcomeScreen; \ No newline at end of file +export default WelcomeScreen; diff --git a/src/screens/welcome/screen/WelcomeScreen.tsx b/src/screens/welcome/screen/WelcomeScreen.tsx index ba492b926..49b2360cd 100644 --- a/src/screens/welcome/screen/WelcomeScreen.tsx +++ b/src/screens/welcome/screen/WelcomeScreen.tsx @@ -20,39 +20,33 @@ const WelcomeScreen = () => { const navigation = useNavigation(); const dispatch = useAppDispatch(); - - const isTermsAccepted = useAppSelector(state => state.application.isTermsAccepted); + const isTermsAccepted = useAppSelector((state) => state.application.isTermsAccepted); const [showAnimation, setShowAnimation] = useState(true); const [isConsentChecked, setIsConsentChecked] = useState(isTermsAccepted); const [appVersion] = useState(VersionNumber.appVersion); - useEffect(() => { _showWelcomeModal(); - }, []) - + }, []); const _showWelcomeModal = () => { - setShowAnimation(true); setTimeout(() => { setShowAnimation(false); }, 3550); - } - + }; const _handleButtonPress = () => { - dispatch(setLastAppVersion(appVersion)) + dispatch(setLastAppVersion(appVersion)); dispatch(setIsTermsAccepted(isConsentChecked)); - navigation.navigate(ROUTES.STACK.MAIN) - } + navigation.navigate(ROUTES.STACK.MAIN); + }; const _onCheckPress = (value, isCheck) => { setIsConsentChecked(isCheck); }; - const _renderInfo = (iconName, headingIntlId, bodyIntlId) => ( { ); - const _renderConsent = () => ( @@ -90,10 +83,8 @@ const WelcomeScreen = () => { ); - return ( - { {intl.formatMessage({ id: 'welcome.title' })} - - - + + {_renderInfo('question', 'welcome.line1_heading', 'welcome.line1_body')} {_renderInfo('emotsmile', 'welcome.line2_heading', 'welcome.line2_body')} {_renderInfo('people', 'welcome.line3_heading', 'welcome.line3_body')} - - {_renderConsent()} { text={intl.formatMessage({ id: 'welcome.get_started' })} /> - {showAnimation && } ); -} - +}; export default WelcomeScreen; diff --git a/src/utils/conversions.ts b/src/utils/conversions.ts index f8a2ee4e1..bbbf77d46 100644 --- a/src/utils/conversions.ts +++ b/src/utils/conversions.ts @@ -6,7 +6,6 @@ export const vestsToHp = (vests, hivePerMVests) => { return (parseFloat(vests) / 1e6) * hivePerMVests; }; - export const hpToVests = (hp, hivePerMVests) => { if (!hp || !hivePerMVests) { return 0; @@ -14,7 +13,6 @@ export const hpToVests = (hp, hivePerMVests) => { return (parseFloat(hp) * 1e6) / hivePerMVests; }; - export const vestsToRshares = (vests: number, votingPower: number, weight: number) => { if (!vests || !votingPower || !weight) { return 0; diff --git a/src/utils/deepLinkParser.ts b/src/utils/deepLinkParser.ts index 433807cb8..4810e0390 100644 --- a/src/utils/deepLinkParser.ts +++ b/src/utils/deepLinkParser.ts @@ -1,7 +1,7 @@ +import get from 'lodash/get'; import { getPost, getUser } from '../providers/hive/dhive'; import postUrlParser from './postUrlParser'; import parseAuthUrl, { AUTH_MODES } from './parseAuthUrl'; -import get from 'lodash/get'; import ROUTES from '../constants/routeNames'; import parsePurchaseUrl from './parsePurchaseUrl'; @@ -14,7 +14,6 @@ export const deepLinkParser = async (url, currentAccount) => { let profile; let keey; - //profess url for post/content const postUrl = postUrlParser(url); console.log('postUrl : ', postUrl); @@ -77,8 +76,8 @@ export const deepLinkParser = async (url, currentAccount) => { //process url for authentication if (!routeName) { const data = parseAuthUrl(url); - if(data){ - const {mode, referredUser, username, code} = data; + if (data) { + const { mode, referredUser, username, code } = data; if (mode === AUTH_MODES.SIGNUP) { routeName = ROUTES.SCREENS.REGISTER; @@ -87,12 +86,12 @@ export const deepLinkParser = async (url, currentAccount) => { }; keey = `${mode}/${referredUser || ''}`; } - + if (mode === AUTH_MODES.AUTH) { routeName = ROUTES.SCREENS.LOGIN; params = { username, - code + code, }; keey = `${mode}/${username || ''}`; } @@ -114,13 +113,12 @@ export const deepLinkParser = async (url, currentAccount) => { routeName = ROUTES.SCREENS.BOOST; params = { username, - productId + productId, }; keey = `${type}/${username || ''}`; } } - return { routeName: routeName, params: params, diff --git a/src/utils/getCurrentHpApr.ts b/src/utils/getCurrentHpApr.ts index f1e9a7c77..70e5efb60 100644 --- a/src/utils/getCurrentHpApr.ts +++ b/src/utils/getCurrentHpApr.ts @@ -1,33 +1,29 @@ - export const getCurrentHpApr = (gprops) => { - // The inflation was set to 9.5% at block 7m - const initialInflationRate = 9.5; - const initialBlock = 7000000; + // The inflation was set to 9.5% at block 7m + const initialInflationRate = 9.5; + const initialBlock = 7000000; - // It decreases by 0.01% every 250k blocks - const decreaseRate = 250000; - const decreasePercentPerIncrement = 0.01; + // It decreases by 0.01% every 250k blocks + const decreaseRate = 250000; + const decreasePercentPerIncrement = 0.01; - // How many increments have happened since block 7m? - const headBlock = gprops.headBlock; - const deltaBlocks = headBlock - initialBlock; - const decreaseIncrements = deltaBlocks / decreaseRate; + // How many increments have happened since block 7m? + const headBlock = gprops.headBlock; + const deltaBlocks = headBlock - initialBlock; + const decreaseIncrements = deltaBlocks / decreaseRate; - // Current inflation rate - let currentInflationRate = - initialInflationRate - - decreaseIncrements * decreasePercentPerIncrement; + // Current inflation rate + let currentInflationRate = + initialInflationRate - decreaseIncrements * decreasePercentPerIncrement; - // Cannot go lower than 0.95% - if (currentInflationRate < 0.95) { - currentInflationRate = 0.95; - } + // Cannot go lower than 0.95% + if (currentInflationRate < 0.95) { + currentInflationRate = 0.95; + } - // Now lets calculate the "APR" - const vestingRewardPercent = gprops.vestingRewardPercent / 10000; - const virtualSupply = gprops.virtualSupply; - const totalVestingFunds = gprops.totalVestingFund; - return ( - (virtualSupply * currentInflationRate * vestingRewardPercent) / totalVestingFunds - ); -}; \ No newline at end of file + // Now lets calculate the "APR" + const vestingRewardPercent = gprops.vestingRewardPercent / 10000; + const virtualSupply = gprops.virtualSupply; + const totalVestingFunds = gprops.totalVestingFund; + return (virtualSupply * currentInflationRate * vestingRewardPercent) / totalVestingFunds; +}; diff --git a/src/utils/image.ts b/src/utils/image.ts index 04a60b541..7e0eea922 100644 --- a/src/utils/image.ts +++ b/src/utils/image.ts @@ -5,7 +5,8 @@ import { proxifyImageSrc } from '@ecency/render-helper'; import { Platform } from 'react-native'; const whatOs = Platform.OS; -const BASE_IMAGE_URL = whatOs === 'android' ? 'https://images.ecency.com/webp' : 'https://images.ecency.com'; +const BASE_IMAGE_URL = + whatOs === 'android' ? 'https://images.ecency.com/webp' : 'https://images.ecency.com'; export const generateSignature = (media, privateKey) => { const STRING = 'ImageSigningChallenge'; @@ -85,7 +86,7 @@ export const catchImageFromMetadata = (meta, format = 'match', thumbnail = false if (meta && meta.image) { const images = meta.image; // console.log('images : ',images); - + if (thumbnail) { return proxifyImageSrc(images[0], 6, 5, format); } @@ -110,9 +111,9 @@ export const getResizedAvatar = (author, sizeString = 'small') => { return `${BASE_IMAGE_URL}/u/${author}/avatar/${sizeString}`; }; -export const getCoverImageUrl = (username:string) => { +export const getCoverImageUrl = (username: string) => { if (!username) { return ''; } - return `${BASE_IMAGE_URL}/u/${username}/cover/` -} + return `${BASE_IMAGE_URL}/u/${username}/cover/`; +}; diff --git a/src/utils/isAndroidOreo.ts b/src/utils/isAndroidOreo.ts index 825d3b48e..cce302b0e 100644 --- a/src/utils/isAndroidOreo.ts +++ b/src/utils/isAndroidOreo.ts @@ -1,9 +1,5 @@ -import { Platform } from "react-native" +import { Platform } from 'react-native'; export default () => { - return Platform.OS === 'android' - && ( - Platform.Version === 26 - || Platform.Version === 27 - ) -} \ No newline at end of file + return Platform.OS === 'android' && (Platform.Version === 26 || Platform.Version === 27); +}; diff --git a/src/utils/parseAuthUrl.ts b/src/utils/parseAuthUrl.ts index 95f5012f8..f11d830bd 100644 --- a/src/utils/parseAuthUrl.ts +++ b/src/utils/parseAuthUrl.ts @@ -1,47 +1,39 @@ - /** * extracts authentication information from deep link url */ - export enum AUTH_MODES { - AUTH = 'AUTH', - SIGNUP = 'SIGNUP' + AUTH = 'AUTH', + SIGNUP = 'SIGNUP', } interface ParsedAuthUrl { - mode: AUTH_MODES; - username?: string | null, - code?: string | null, - referredUser?: string | null, + mode: AUTH_MODES; + username?: string | null; + code?: string | null; + referredUser?: string | null; } export default (urlString: string): ParsedAuthUrl | null => { + const url = new URL(urlString); + console.log(JSON.stringify(url, null, '\t')); + if (url.pathname === '/signup') { + const referredUser = url.searchParams.get('referral'); + return { + mode: AUTH_MODES.SIGNUP, + referredUser, + }; + } else if (url.pathname === '/auth') { + const username = url.searchParams.get('username'); + const code = url.searchParams.get('code'); //TODO: process encryption when in place - const url = new URL(urlString); - console.log(JSON.stringify(url, null, '\t')); - if (url.pathname === '/signup') { - const referredUser = url.searchParams.get('referral') - return { - mode: AUTH_MODES.SIGNUP, - referredUser + return { + mode: AUTH_MODES.AUTH, - } - } - else if (url.pathname === '/auth') { - const username = url.searchParams.get('username'); - const code = url.searchParams.get('code'); //TODO: process encryption when in place - - return { - mode: AUTH_MODES.AUTH, - - username, - code - - } - } - - return null - -} + username, + code, + }; + } + return null; +}; diff --git a/src/utils/parsePurchaseUrl.ts b/src/utils/parsePurchaseUrl.ts index 86c78494f..2d2807469 100644 --- a/src/utils/parsePurchaseUrl.ts +++ b/src/utils/parsePurchaseUrl.ts @@ -1,28 +1,26 @@ - /** * extracts purchase information from deep link url i-e https://ecency.com/purchase?type=boost&username=demo.com - * + * */ - export enum PURCHASE_TYPES { - POINTS ='points', - BOOST ='boost' + POINTS = 'points', + BOOST = 'boost', } -export default (urlString:string) => { - const url = new URL(urlString); - console.log(JSON.stringify(url, null, '\t')); - if(url.pathname === '/purchase'){ - const type = url.searchParams.get('type'); - const username = url.searchParams.get('username'); - const productId = url.searchParams.get('product_id'); - return { - type, - username, - productId - } - } +export default (urlString: string) => { + const url = new URL(urlString); + console.log(JSON.stringify(url, null, '\t')); + if (url.pathname === '/purchase') { + const type = url.searchParams.get('type'); + const username = url.searchParams.get('username'); + const productId = url.searchParams.get('product_id'); + return { + type, + username, + productId, + }; + } - return null; -} \ No newline at end of file + return null; +}; diff --git a/src/utils/postParser.tsx b/src/utils/postParser.tsx index 7a6b2055c..5ab549c7f 100644 --- a/src/utils/postParser.tsx +++ b/src/utils/postParser.tsx @@ -14,9 +14,7 @@ const webp = Platform.OS === 'ios' ? false : true; export const parsePosts = (posts, currentUserName) => { if (posts) { - const formattedPosts = posts.map((post) => - parsePost(post, currentUserName, false, true), - ); + const formattedPosts = posts.map((post) => parsePost(post, currentUserName, false, true)); return formattedPosts; } return null; @@ -42,7 +40,6 @@ export const parsePost = (post, currentUserName, isPromoted, isList = false) => //adjust tags type as it can be string sometimes; post = parseTags(post); - //extract cover image and thumbnail from post body post.image = catchPostImage(post, 600, 500, webp ? 'webp' : 'match'); post.thumbnail = catchPostImage(post, 10, 7, webp ? 'webp' : 'match'); @@ -63,8 +60,6 @@ export const parsePost = (post, currentUserName, isPromoted, isList = false) => post.total_payout = totalPayout; - - //stamp posts with fetched time; post.post_fetched_at = new Date().getTime(); @@ -81,7 +76,6 @@ export const parsePost = (post, currentUserName, isPromoted, isList = false) => return post; }; - export const parseCommentThreads = async (commentsMap: any, author: string, permlink: string) => { const MAX_THREAD_LEVEL = 3; const comments = []; @@ -90,7 +84,6 @@ export const parseCommentThreads = async (commentsMap: any, author: string, perm return null; } - //traverse map to curate threads const parseReplies = (commentsMap: any, replies: any[], level: number) => { if (replies && replies.length > 0 && MAX_THREAD_LEVEL > level) { @@ -98,7 +91,7 @@ export const parseCommentThreads = async (commentsMap: any, author: string, perm const comment = commentsMap[pathKey]; if (comment) { const parsedComment = parseComment(comment); - parsedComment.replies = parseReplies(commentsMap, parsedComment.replies, level + 1) + parsedComment.replies = parseReplies(commentsMap, parsedComment.replies, level + 1); return parsedComment; } else { return null; @@ -106,28 +99,24 @@ export const parseCommentThreads = async (commentsMap: any, author: string, perm }); } return []; - } + }; for (const key in commentsMap) { if (commentsMap.hasOwnProperty(key)) { - const comment = commentsMap[key]; //prcoess first level comment if (comment && comment.parent_author === author && comment.parent_permlink === permlink) { let _parsedComment = parseComment(comment); - _parsedComment.replies = parseReplies(commentsMap, _parsedComment.replies, 1) + _parsedComment.replies = parseReplies(commentsMap, _parsedComment.replies, 1); comments.push(_parsedComment); } - } } return comments; }; - - export const parseComments = (comments: any[]) => { if (!comments) { return null; @@ -166,7 +155,12 @@ export const parseComment = (comment: any) => { comment.total_payout = totalPayout; - comment.isDeletable = !(comment.active_votes?.length > 0 || comment.children > 0 || comment.net_rshares > 0 || comment.is_paidout); + comment.isDeletable = !( + comment.active_votes?.length > 0 || + comment.children > 0 || + comment.net_rshares > 0 || + comment.is_paidout + ); //stamp comments with fetched time; comment.post_fetched_at = new Date().getTime(); @@ -204,8 +198,8 @@ export const parseActiveVotes = (post) => { const totalPayout = post.total_payout || parseFloat(post.pending_payout_value) + - parseFloat(post.total_payout_value) + - parseFloat(post.curator_payout_value); + parseFloat(post.total_payout_value) + + parseFloat(post.curator_payout_value); const voteRshares = post.active_votes.reduce((a, b) => a + parseFloat(b.rshares), 0); const ratio = totalPayout / voteRshares || 0; @@ -222,7 +216,6 @@ export const parseActiveVotes = (post) => { return post.active_votes; }; - const parseTags = (post: any) => { if (post.json_metadata) { let _tags = get(post.json_metadata, 'tags', []); @@ -233,8 +226,8 @@ const parseTags = (post: any) => { } else if (_tags.indexOf(',') > -1) { separator = ','; } - post.json_metadata.tags = _tags.split(separator) + post.json_metadata.tags = _tags.split(separator); } } return post; -} \ No newline at end of file +}; diff --git a/src/utils/showLoginAlert.ts b/src/utils/showLoginAlert.ts index b6bea308c..04f7e43a9 100644 --- a/src/utils/showLoginAlert.ts +++ b/src/utils/showLoginAlert.ts @@ -1,5 +1,5 @@ import { Alert } from 'react-native'; -import ROUTES from '../../src/constants/routeNames'; +import ROUTES from '../constants/routeNames'; import { navigate } from '../navigation/service'; const showLoginAlert = ({ intl }) => { @@ -15,7 +15,7 @@ const showLoginAlert = ({ intl }) => { { text: intl.formatMessage({ id: 'login.login' }), onPress: () => { - navigate({routeName:ROUTES.SCREENS.LOGIN}); + navigate({ routeName: ROUTES.SCREENS.LOGIN }); }, }, ],