mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-11-25 21:53:04 +03:00
lint
This commit is contained in:
parent
d34fa30f40
commit
3c63b00f87
3
index.js
3
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
|
||||
|
@ -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,7 +106,11 @@ 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
|
||||
@ -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',
|
||||
|
@ -1,2 +1,2 @@
|
||||
export * from './optionsModal';
|
||||
export * from './progressBar'
|
||||
export * from './progressBar';
|
||||
|
@ -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,
|
||||
container: {
|
||||
backgroundColor: '$primaryLightBackground',
|
||||
flexDirection: 'row',
|
||||
borderRadius: 16,
|
||||
height: 16,
|
||||
alignSelf: 'stretch',
|
||||
marginHorizontal: 8,
|
||||
marginBottom: 12,
|
||||
},
|
||||
filled:{
|
||||
borderRadius:16,
|
||||
backgroundColor:'$primaryBlue'
|
||||
filled: {
|
||||
borderRadius: 16,
|
||||
backgroundColor: '$primaryBlue',
|
||||
},
|
||||
});
|
||||
|
@ -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}
|
||||
export const ProgressBar = ({ progress }) => {
|
||||
const containerStyle = { ...styles.container };
|
||||
const filledStyle = { ...styles.filled, flex: progress };
|
||||
const unfilledStyle = { flex: 100 - progress };
|
||||
return (
|
||||
<View style={containerStyle}>
|
||||
<View style={filledStyle} />
|
||||
<View style={unfilledStyle} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -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 = ({
|
||||
export const AutoHeightImage = ({
|
||||
contentWidth,
|
||||
imgUrl,
|
||||
isAnchored,
|
||||
activeOpacity,
|
||||
onPress
|
||||
}:AutoHeightImageProps) => {
|
||||
|
||||
|
||||
onPress,
|
||||
}: AutoHeightImageProps) => {
|
||||
const [imgWidth, setImgWidth] = useState(contentWidth);
|
||||
const [imgHeight, setImgHeight] = useState(imgWidth * (9/16))
|
||||
const [imgHeight, setImgHeight] = useState(imgWidth * (9 / 16));
|
||||
const [onLoadCalled, setOnLoadCalled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
_fetchImageBounds();
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
const _fetchImageBounds = () => {
|
||||
Image.getSize(imgUrl, (width, height)=>{
|
||||
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')
|
||||
}
|
||||
width: imgWidth - 10,
|
||||
height: imgHeight,
|
||||
backgroundColor: onLoadCalled ? 'transparent' : EStyleSheet.value('$primaryGray'),
|
||||
};
|
||||
|
||||
const _onLoad = () => {
|
||||
setOnLoadCalled(true);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={onPress} disabled={isAnchored} activeOpacity={activeOpacity || 1}>
|
||||
<FastImage
|
||||
style={imgStyle}
|
||||
source={{uri:imgUrl}}
|
||||
source={{ uri: imgUrl }}
|
||||
resizeMode={FastImage.resizeMode.contain}
|
||||
onLoad={_onLoad}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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()}
|
||||
/>
|
||||
) : (
|
||||
<ActivityIndicator style={styles.textButtonWrapper} color={EStyleSheet.value('$primaryBlue')} />
|
||||
<ActivityIndicator
|
||||
style={styles.textButtonWrapper}
|
||||
color={EStyleSheet.value('$primaryBlue')}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
@ -229,13 +227,15 @@ const BasicHeaderView = ({
|
||||
text={rightButtonText}
|
||||
/>
|
||||
) : (
|
||||
<ActivityIndicator style={[styles.textButtonWrapper]} color={EStyleSheet.value('$primaryBlue')} />
|
||||
<ActivityIndicator
|
||||
style={[styles.textButtonWrapper]}
|
||||
color={EStyleSheet.value('$primaryBlue')}
|
||||
/>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</View>
|
||||
|
||||
|
||||
<OptionsModal
|
||||
ref={rewardMenuRef}
|
||||
options={[
|
||||
@ -248,7 +248,6 @@ const BasicHeaderView = ({
|
||||
title="Reward"
|
||||
onPress={_handleRewardMenuSelect}
|
||||
/>
|
||||
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
@ -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,7 +94,10 @@ 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.
|
||||
@ -242,7 +243,7 @@ const BeneficiarySelectionContent = ({
|
||||
onChange={(value) => _onWeightInputChange(value)}
|
||||
selectTextOnFocus={true}
|
||||
autoFocus={true}
|
||||
returnKeyType={'next'}
|
||||
returnKeyType="next"
|
||||
keyboardType="numeric"
|
||||
/>
|
||||
</View>
|
||||
@ -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 (
|
||||
<View style={styles.container}>
|
||||
<Text style={labelStyle || styles.settingLabel}>{label || intl.formatMessage({ id: 'editor.beneficiaries' })}</Text>
|
||||
<Text style={labelStyle || styles.settingLabel}>
|
||||
{label || intl.formatMessage({ id: 'editor.beneficiaries' })}
|
||||
</Text>
|
||||
<FlatList
|
||||
data={beneficiaries}
|
||||
renderItem={_renderItem}
|
||||
|
@ -2,64 +2,63 @@ import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { getBottomSpace } from 'react-native-iphone-x-helper';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
|
||||
sheetContent: {
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
position:'absolute',
|
||||
bottom:0,
|
||||
left:0,
|
||||
right:0,
|
||||
zIndex:999
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 999,
|
||||
},
|
||||
thumbStyle:{
|
||||
width:72,
|
||||
height:72,
|
||||
marginVertical:8,
|
||||
marginRight:8,
|
||||
borderRadius:12,
|
||||
backgroundColor:'$primaryLightGray'
|
||||
thumbStyle: {
|
||||
width: 72,
|
||||
height: 72,
|
||||
marginVertical: 8,
|
||||
marginRight: 8,
|
||||
borderRadius: 12,
|
||||
backgroundColor: '$primaryLightGray',
|
||||
},
|
||||
selectedStyle:{
|
||||
borderWidth:4,
|
||||
borderColor:'$primaryBlack'
|
||||
selectedStyle: {
|
||||
borderWidth: 4,
|
||||
borderColor: '$primaryBlack',
|
||||
},
|
||||
settingLabel:{
|
||||
settingLabel: {
|
||||
color: '$primaryDarkGray',
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
flexGrow: 1,
|
||||
textAlign:'left',
|
||||
textAlign: 'left',
|
||||
},
|
||||
listContainer:{
|
||||
paddingBottom:getBottomSpace() + 16,
|
||||
listContainer: {
|
||||
paddingBottom: getBottomSpace() + 16,
|
||||
},
|
||||
container:{
|
||||
paddingVertical:16
|
||||
container: {
|
||||
paddingVertical: 16,
|
||||
},
|
||||
bodyWrapper: { flex: 1, paddingTop: 20, paddingBottom:20},
|
||||
inputWrapper: { flexDirection: 'row', alignItems: 'center'},
|
||||
contentLabel: { color: '$iconColor', marginTop:4, textAlign:'left' },
|
||||
weightInput: {width:80},
|
||||
weightFormInput: { flex:1, color: '$primaryBlack', paddingLeft: 12 },
|
||||
bodyWrapper: { flex: 1, paddingTop: 20, paddingBottom: 20 },
|
||||
inputWrapper: { flexDirection: 'row', alignItems: 'center' },
|
||||
contentLabel: { color: '$iconColor', marginTop: 4, textAlign: 'left' },
|
||||
weightInput: { width: 80 },
|
||||
weightFormInput: { flex: 1, color: '$primaryBlack', paddingLeft: 12 },
|
||||
weightFormInputWrapper: { marginTop: 8 },
|
||||
usernameInput: { flex:1, color: '$primaryBlack', marginLeft: 16, },
|
||||
usernameInput: { flex: 1, color: '$primaryBlack', marginLeft: 16 },
|
||||
usernameFormInputWrapper: { marginTop: 8, marginRight: 12 },
|
||||
footerWrapper: { paddingTop:16 },
|
||||
footerWrapper: { paddingTop: 16 },
|
||||
saveButton: {
|
||||
width: 140,
|
||||
height: 44,
|
||||
alignSelf: 'flex-end',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
doneButton:{borderRadius:16, backgroundColor:'$primaryBlue'},
|
||||
thumbSelectContainer:{
|
||||
marginTop:12,
|
||||
doneButton: { borderRadius: 16, backgroundColor: '$primaryBlue' },
|
||||
thumbSelectContainer: {
|
||||
marginTop: 12,
|
||||
},
|
||||
checkBoxHeader: {
|
||||
width: 50,
|
||||
},
|
||||
checkBoxContainer: {
|
||||
width: 50,
|
||||
marginTop:12,
|
||||
}
|
||||
marginTop: 12,
|
||||
},
|
||||
});
|
||||
|
@ -1,11 +1,12 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { SafeAreaView, View, TouchableOpacity } from 'react-native';
|
||||
|
||||
|
||||
// Components
|
||||
// import TabBar from './tabbar';
|
||||
|
||||
// Constants
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
|
||||
import ROUTES from '../../../constants/routeNames';
|
||||
|
||||
// Styles
|
||||
@ -13,40 +14,29 @@ import styles from './bottomTabBarStyles';
|
||||
import Icon, { IconContainer } from '../../icon';
|
||||
import scalePx from '../../../utils/scalePx';
|
||||
import { updateActiveBottomTab } from '../../../redux/actions/uiAction';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const BottomTabBarView = ({
|
||||
state : { routes , index },
|
||||
state: { routes, index },
|
||||
navigation,
|
||||
descriptors
|
||||
}:BottomTabBarProps) => {
|
||||
|
||||
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 = <Icon {..._iconProps}/>
|
||||
let _tabBarIcon = <Icon {..._iconProps} />;
|
||||
switch (route.name) {
|
||||
case ROUTES.TABBAR.NOTIFICATION:
|
||||
_tabBarIcon = (<IconContainer
|
||||
isBadge badgeType="notification" {..._iconProps}/>)
|
||||
_tabBarIcon = <IconContainer isBadge badgeType="notification" {..._iconProps} />;
|
||||
break;
|
||||
case ROUTES.TABBAR.POST_BUTTON:
|
||||
_iconProps.iconType = "MaterialCommunityIcons"
|
||||
_tabBarIcon = <Icon {..._iconProps} />
|
||||
_iconProps.iconType = 'MaterialCommunityIcons';
|
||||
_tabBarIcon = <Icon {..._iconProps} />;
|
||||
break;
|
||||
}
|
||||
|
||||
return (
|
||||
<View key={route.key} style={{ flex: 1, alignItems: 'center' }}>
|
||||
<TouchableOpacity onPress={() => _jumpTo(route, isFocused)}>
|
||||
{_tabBarIcon}
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => _jumpTo(route, isFocused)}>{_tabBarIcon}</TouchableOpacity>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
return (
|
||||
<SafeAreaView style={styles.wrapper}>
|
||||
{_tabButtons}
|
||||
</SafeAreaView>
|
||||
);
|
||||
});
|
||||
|
||||
return <SafeAreaView style={styles.wrapper}>{_tabButtons}</SafeAreaView>;
|
||||
};
|
||||
|
||||
export default BottomTabBarView;
|
||||
|
@ -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<AnimatedView>(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 {
|
||||
@ -121,34 +120,32 @@ const CommentView = ({
|
||||
}
|
||||
|
||||
setIsPressedShowButton(true);
|
||||
|
||||
} else if (openReplyThread) {
|
||||
openReplyThread();
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
const _handleCacheVoteIncrement = () => {
|
||||
const _handleCacheVoteIncrement = () => {
|
||||
//fake increment vote using based on local change
|
||||
setCacheVoteIcrement(1);
|
||||
};
|
||||
};
|
||||
|
||||
const _incrementRepliesCount = () => {
|
||||
const _incrementRepliesCount = () => {
|
||||
if (commentNumber > 1 && incrementRepliesCount) {
|
||||
incrementRepliesCount();
|
||||
}
|
||||
setChildCount(childCount + 1);
|
||||
}
|
||||
};
|
||||
|
||||
const _handleOnReplyPress = () => {
|
||||
const _handleOnReplyPress = () => {
|
||||
if (isLoggedIn) {
|
||||
dispatch(showReplyModal(comment));
|
||||
} else {
|
||||
console.log('Not LoggedIn');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _renderReadMoreButton = () => (
|
||||
const _renderReadMoreButton = () => (
|
||||
<TextWithIcon
|
||||
wrapperStyle={styles.rightButton}
|
||||
textStyle={!isPressedShowButton && styles.moreText}
|
||||
@ -157,21 +154,14 @@ const _renderReadMoreButton = () => (
|
||||
iconStyle={styles.iconStyle}
|
||||
iconSize={16}
|
||||
onPress={() => openReplyThread && openReplyThread()}
|
||||
text={
|
||||
!isPressedShowButton
|
||||
? intl.formatMessage({ id: 'comments.read_more' })
|
||||
: ''
|
||||
}
|
||||
text={!isPressedShowButton ? intl.formatMessage({ id: 'comments.read_more' }) : ''}
|
||||
/>
|
||||
);
|
||||
|
||||
)
|
||||
|
||||
const _renderReplies = () => {
|
||||
|
||||
|
||||
const _renderReplies = () => {
|
||||
return (
|
||||
<AnimatedView ref={repliesContainerRef}>
|
||||
{_isShowSubComments &&
|
||||
{_isShowSubComments && (
|
||||
<Comments
|
||||
isShowComments={isShowComments}
|
||||
commentNumber={commentNumber + 1}
|
||||
@ -189,15 +179,14 @@ const _renderReplies = () => {
|
||||
fetchedAt={fetchedAt}
|
||||
incrementRepliesCount={_incrementRepliesCount}
|
||||
handleOnReplyPress={_handleOnReplyPress}
|
||||
/>}
|
||||
/>
|
||||
)}
|
||||
</AnimatedView>
|
||||
);
|
||||
};
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const _renderComment = () => {
|
||||
return ((
|
||||
const _renderComment = () => {
|
||||
return (
|
||||
<View style={[{ marginLeft: 2, marginTop: -6 }]}>
|
||||
<CommentBody
|
||||
commentDepth={comment.depth}
|
||||
@ -211,21 +200,14 @@ const _renderComment = () => {
|
||||
/>
|
||||
|
||||
<Fragment>
|
||||
<View style={styles.footerWrapper}>
|
||||
{_renderActionPanel()}
|
||||
</View>
|
||||
{commentNumber > 1 &&
|
||||
childCount > 0 &&
|
||||
!replies?.length &&
|
||||
_renderReadMoreButton()
|
||||
}
|
||||
<View style={styles.footerWrapper}>{_renderActionPanel()}</View>
|
||||
{commentNumber > 1 && childCount > 0 && !replies?.length && _renderReadMoreButton()}
|
||||
</Fragment>
|
||||
</View>
|
||||
))
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const _renderActionPanel = () => {
|
||||
const _renderActionPanel = () => {
|
||||
return (
|
||||
<>
|
||||
<Upvote
|
||||
@ -261,7 +243,6 @@ const _renderActionPanel = () => {
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
{currentAccountUsername === comment.author && (
|
||||
<Fragment>
|
||||
<IconButton
|
||||
@ -300,7 +281,6 @@ const _renderActionPanel = () => {
|
||||
</Fragment>
|
||||
)}
|
||||
|
||||
|
||||
{commentNumber === 1 && childCount > 0 && (
|
||||
<View style={styles.rightButtonWrapper}>
|
||||
<TextWithIcon
|
||||
@ -316,14 +296,13 @@ const _renderActionPanel = () => {
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const customContainerStyle = commentNumber > 2 ? { marginLeft: 44 } : null
|
||||
const customContainerStyle = commentNumber > 2 ? { marginLeft: 44 } : null;
|
||||
|
||||
return (
|
||||
return (
|
||||
<Fragment>
|
||||
<View style={{ ...styles.commentContainer, ...customContainerStyle }}>
|
||||
<PostHeaderDescription
|
||||
@ -345,7 +324,7 @@ return (
|
||||
{commentNumber > 0 && _renderReplies()}
|
||||
</View>
|
||||
</Fragment>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default CommentView;
|
||||
|
@ -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<any>();
|
||||
|
||||
|
||||
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 (
|
||||
<TextButton
|
||||
@ -87,7 +83,6 @@ const CommentsView = ({
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const _renderItem = ({ item }) => {
|
||||
return (
|
||||
<Comment
|
||||
@ -115,29 +110,30 @@ const CommentsView = ({
|
||||
fetchedAt={fetchedAt}
|
||||
incrementRepliesCount={incrementRepliesCount}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const styleOerride = commentNumber > 1 ? {
|
||||
const styleOerride =
|
||||
commentNumber > 1
|
||||
? {
|
||||
backgroundColor: EStyleSheet.value('$primaryLightBackground'),
|
||||
marginTop: 8,
|
||||
} : null
|
||||
}
|
||||
: null;
|
||||
|
||||
const _renderEmptyContent = () => {
|
||||
if(commentNumber > 1){
|
||||
if (commentNumber > 1) {
|
||||
return;
|
||||
}
|
||||
const _onPress = () => {
|
||||
handleOnReplyPress()
|
||||
}
|
||||
handleOnReplyPress();
|
||||
};
|
||||
return (
|
||||
<Text onPress={_onPress} style={styles.emptyText}>
|
||||
{intl.formatMessage({ id: "comments.no_comments" })}
|
||||
{intl.formatMessage({ id: 'comments.no_comments' })}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
|
@ -1,12 +1,12 @@
|
||||
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;
|
||||
@ -17,12 +17,12 @@ export const WriteCommentButton = forwardRef(({ onPress }, ref) => {
|
||||
|
||||
const animatedContainer = useRef<AnimatedView>();
|
||||
|
||||
const isLoggedIn = useAppSelector(state => state.application.isLoggedIn);
|
||||
const currentAccount = useAppSelector(state => state.account.currentAccount);
|
||||
const isLoggedIn = useAppSelector((state) => state.application.isLoggedIn);
|
||||
const currentAccount = useAppSelector((state) => state.account.currentAccount);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
bounce: () => {
|
||||
console.log("bouncing")
|
||||
console.log('bouncing');
|
||||
if (animatedContainer.current) {
|
||||
animatedContainer.current.swing(1000);
|
||||
}
|
||||
@ -31,13 +31,13 @@ export const WriteCommentButton = forwardRef(({ onPress }, ref) => {
|
||||
|
||||
const _onPress = () => {
|
||||
if (!isLoggedIn) {
|
||||
showLoginAlert({ intl })
|
||||
showLoginAlert({ intl });
|
||||
return;
|
||||
}
|
||||
if (onPress) {
|
||||
onPress();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<AnimatedView ref={animatedContainer}>
|
||||
@ -46,12 +46,11 @@ export const WriteCommentButton = forwardRef(({ onPress }, ref) => {
|
||||
<UserAvatar username={currentAccount.username} />
|
||||
<View style={styles.inputContainer}>
|
||||
<Text style={styles.inputPlaceholder}>
|
||||
{intl.formatMessage({id:'quick_reply.placeholder'})}
|
||||
{intl.formatMessage({ id: 'quick_reply.placeholder' })}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
</AnimatedView>
|
||||
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -5,32 +5,32 @@ import getWindowDimensions from '../../utils/getWindowDimensions';
|
||||
export default EStyleSheet.create({
|
||||
modalStyle: {
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
margin:0,
|
||||
paddingTop:32,
|
||||
paddingBottom:8,
|
||||
margin: 0,
|
||||
paddingTop: 32,
|
||||
paddingBottom: 8,
|
||||
},
|
||||
|
||||
sheetContent: {
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
},
|
||||
|
||||
container:{
|
||||
marginTop:16,
|
||||
marginBottom:44,
|
||||
paddingHorizontal:24,
|
||||
alignItems:'center',
|
||||
justifyContent:'space-between',
|
||||
container: {
|
||||
marginTop: 16,
|
||||
marginBottom: 44,
|
||||
paddingHorizontal: 24,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
} as ViewStyle,
|
||||
|
||||
imageStyle:{
|
||||
marginTop:8,
|
||||
height:150,
|
||||
width:150,
|
||||
imageStyle: {
|
||||
marginTop: 8,
|
||||
height: 150,
|
||||
width: 150,
|
||||
} as ImageStyle,
|
||||
|
||||
textContainer:{
|
||||
marginTop:32,
|
||||
marginBottom:44,
|
||||
textContainer: {
|
||||
marginTop: 32,
|
||||
marginBottom: 44,
|
||||
} as ViewStyle,
|
||||
|
||||
title: {
|
||||
@ -47,47 +47,41 @@ export default EStyleSheet.create({
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
marginTop:4,
|
||||
marginTop: 4,
|
||||
} as TextStyle,
|
||||
|
||||
btnText:{
|
||||
color:'$pureWhite'
|
||||
btnText: {
|
||||
color: '$pureWhite',
|
||||
} as TextStyle,
|
||||
|
||||
button:{
|
||||
|
||||
backgroundColor:'$primaryBlue',
|
||||
width:150,
|
||||
paddingVertical:16,
|
||||
borderRadius:32,
|
||||
justifyContent:'center',
|
||||
alignItems:'center'
|
||||
button: {
|
||||
backgroundColor: '$primaryBlue',
|
||||
width: 150,
|
||||
paddingVertical: 16,
|
||||
borderRadius: 32,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
} as ViewStyle,
|
||||
|
||||
|
||||
actionPanel:{
|
||||
width:'100%',
|
||||
flexDirection:'row',
|
||||
justifyContent:'space-around',
|
||||
alignItems:'center',
|
||||
actionPanel: {
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-around',
|
||||
alignItems: 'center',
|
||||
} as ViewStyle,
|
||||
|
||||
checkView: {
|
||||
width:getWindowDimensions().width - 80,
|
||||
width: getWindowDimensions().width - 80,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems:'center',
|
||||
alignItems: 'center',
|
||||
marginHorizontal: 20,
|
||||
marginVertical:4,
|
||||
marginVertical: 4,
|
||||
} as ViewStyle,
|
||||
|
||||
|
||||
informationText: {
|
||||
color: '$primaryBlack',
|
||||
margin: 10,
|
||||
fontSize:18,
|
||||
fontSize: 18,
|
||||
} as TextStyle,
|
||||
|
||||
|
||||
|
||||
})
|
||||
});
|
||||
|
@ -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';
|
||||
@ -42,11 +42,11 @@ const renderDropdownRow = (
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
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 = ({
|
||||
<ModalDropdown
|
||||
ref={dropdownRef}
|
||||
renderRowComponent={TouchableHighlight}
|
||||
renderRowProps={{ underlayColor: EStyleSheet.value('$modalBackground'), style:styles.rowWrapper}}
|
||||
renderRowProps={{
|
||||
underlayColor: EStyleSheet.value('$modalBackground'),
|
||||
style: styles.rowWrapper,
|
||||
}}
|
||||
style={[!style ? styles.button : style]}
|
||||
textStyle={[textStyle || styles.buttonText]}
|
||||
dropdownStyle={[styles.dropdown, dropdownStyle, { height: 32 * (options.length + 1.5) }]}
|
||||
@ -94,13 +97,11 @@ const DropdownButtonView = ({
|
||||
dropdownRowWrapper,
|
||||
)
|
||||
}
|
||||
adjustFrame={(style: any) => adjustDropdownFrame(style) }
|
||||
adjustFrame={(style: any) => adjustDropdownFrame(style)}
|
||||
>
|
||||
{isHasChildIcon && !isLoading ? (
|
||||
<View style={styles.childrenWrapper}>
|
||||
<Text style={[textStyle || styles.buttonText]}>
|
||||
{defaultText}
|
||||
</Text>
|
||||
<Text style={[textStyle || styles.buttonText]}>{defaultText}</Text>
|
||||
<View style={[styles.iconWrapper, childIconWrapperStyle && childIconWrapperStyle]}>
|
||||
<Icon
|
||||
style={[styles.dropdownIcon, iconStyle]}
|
||||
|
@ -16,8 +16,7 @@ import { Tag } from '../../../basicUIElements';
|
||||
import { isCommunity } from '../../../../utils/communityValidation';
|
||||
import { toastNotification } from '../../../../redux/actions/uiAction';
|
||||
|
||||
|
||||
const SEPARATOR_REGEX = /[,\s]/
|
||||
const SEPARATOR_REGEX = /[,\s]/;
|
||||
|
||||
const TagInput = ({ value, handleTagChanged, intl, isPreviewActive, autoFocus, setCommunity }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
@ -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 && (
|
||||
<AnimatedView
|
||||
ref={containerRef}
|
||||
style={styles.container}
|
||||
animation='slideInDown'
|
||||
duration={500}>
|
||||
|
||||
animation="slideInDown"
|
||||
duration={500}
|
||||
>
|
||||
<View style={styles.contentContainer}>
|
||||
|
||||
<TouchableOpacity onPress={_onPress} style={{ flexShrink: 1 }}>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', marginRight: 24 }}>
|
||||
<UserAvatar username={username} />
|
||||
|
||||
<View style={{ flexShrink: 1 }}>
|
||||
<Text style={styles.text} numberOfLines={1}>{title}</Text>
|
||||
<Text style={styles.text} numberOfLines={1}>{body}</Text>
|
||||
<Text style={styles.text} numberOfLines={1}>
|
||||
{title}
|
||||
</Text>
|
||||
<Text style={styles.text} numberOfLines={1}>
|
||||
{body}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
|
||||
<IconButton
|
||||
name='close'
|
||||
color="white"
|
||||
size={28}
|
||||
onPress={hide}
|
||||
/>
|
||||
<IconButton name="close" color="white" size={28} onPress={hide} />
|
||||
</View>
|
||||
</AnimatedView>
|
||||
)
|
||||
}
|
||||
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default ForegroundNotification;
|
||||
|
@ -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,
|
||||
},
|
||||
});
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
@ -46,13 +46,8 @@ const HeaderView = ({
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const _renderAvatar = () => (
|
||||
<TouchableOpacity
|
||||
style={styles.avatarWrapper}
|
||||
onPress={handleOpenDrawer}
|
||||
disabled={isReverse}
|
||||
>
|
||||
<TouchableOpacity style={styles.avatarWrapper} onPress={handleOpenDrawer} disabled={isReverse}>
|
||||
<LinearGradient
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
@ -69,14 +64,17 @@ const HeaderView = ({
|
||||
/>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
const _renderTitle = () => (
|
||||
<>
|
||||
{displayName || username ? (
|
||||
<View style={[styles.titleWrapper, isReverse && styles.titleWrapperReverse]}>
|
||||
{displayName && <Text numberOfLines={1} style={styles.title}>{displayName}</Text>}
|
||||
{displayName && (
|
||||
<Text numberOfLines={1} style={styles.title}>
|
||||
{displayName}
|
||||
</Text>
|
||||
)}
|
||||
<Text style={styles.subTitle}>
|
||||
{`@${username}`}
|
||||
{reputation && ` (${reputation})`}
|
||||
@ -94,8 +92,7 @@ const HeaderView = ({
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
const _renderActionButtons = () => (
|
||||
<>
|
||||
@ -123,11 +120,10 @@ const HeaderView = ({
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
);
|
||||
|
||||
return (
|
||||
<SafeAreaView style={[styles.container, isReverse && styles.containerReverse]}>
|
||||
|
||||
{!hideUser && (
|
||||
<>
|
||||
<SearchModal
|
||||
|
@ -1,21 +1,15 @@
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import {
|
||||
Platform,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import { Platform, Text, TouchableOpacity, View, ActivityIndicator } from 'react-native';
|
||||
import { renderPostBody } from '@ecency/render-helper';
|
||||
import { ScrollView } from 'react-native-gesture-handler';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import { MainButton, PostBody, TextButton } from '..';
|
||||
import styles from './insertLinkModalStyles';
|
||||
import TextInput from '../textInput';
|
||||
import { delay } from '../../utils/editor';
|
||||
import { isStringWebLink } from '../markdownEditor/children/formats/utils';
|
||||
import { renderPostBody } from '@ecency/render-helper';
|
||||
import { ScrollView } from 'react-native-gesture-handler';
|
||||
import applyWebLinkFormat from '../markdownEditor/children/formats/applyWebLinkFormat';
|
||||
import Clipboard from '@react-native-clipboard/clipboard';
|
||||
import getWindowDimensions from '../../utils/getWindowDimensions';
|
||||
import Modal from '../modal';
|
||||
|
||||
@ -49,7 +43,6 @@ export const InsertLinkModal = forwardRef(
|
||||
const labelInputRef = useRef(null);
|
||||
const urlInputRef = useRef(null);
|
||||
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
showModal: async ({ selectedText, selection }) => {
|
||||
if (selectedText) {
|
||||
@ -141,8 +134,8 @@ export const InsertLinkModal = forwardRef(
|
||||
<View style={styles.floatingContainer}>
|
||||
<TextButton
|
||||
style={styles.cancelButton}
|
||||
onPress={() => setVisible(false)}// sheetModalRef.current?.setModalVisible(false)}
|
||||
text={'Cancel'}
|
||||
onPress={() => setVisible(false)} // sheetModalRef.current?.setModalVisible(false)}
|
||||
text="Cancel"
|
||||
/>
|
||||
<MainButton
|
||||
style={styles.insertBtn}
|
||||
@ -277,13 +270,13 @@ export const InsertLinkModal = forwardRef(
|
||||
) : null}
|
||||
</View>
|
||||
</ScrollView>
|
||||
{isLoading && <ActivityIndicator color={'$primaryBlue'} />}
|
||||
{isLoading && <ActivityIndicator color="$primaryBlue" />}
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
const _renderContent = (
|
||||
<ScrollView style={styles.container} keyboardShouldPersistTaps={'handled'}>
|
||||
<ScrollView style={styles.container} keyboardShouldPersistTaps="handled">
|
||||
{_renderInputs()}
|
||||
{_renderPreview()}
|
||||
{_renderFloatingPanel()}
|
||||
@ -291,7 +284,6 @@ export const InsertLinkModal = forwardRef(
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
<Modal
|
||||
isOpen={visible}
|
||||
handleOnModalClose={_handleOnCloseSheet}
|
||||
@ -302,7 +294,6 @@ export const InsertLinkModal = forwardRef(
|
||||
>
|
||||
{_renderContent}
|
||||
</Modal>
|
||||
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -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<typeof UploadsGalleryModal>(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',
|
||||
() => {
|
||||
const keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', () => {
|
||||
setKeyboardVisible(true); // or some other action
|
||||
}
|
||||
);
|
||||
const keyboardDidHideListener = Keyboard.addListener(
|
||||
'keyboardDidHide',
|
||||
() => {
|
||||
});
|
||||
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);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@ -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({
|
||||
const consY = useMemo(
|
||||
() =>
|
||||
translateY.current.interpolate({
|
||||
inputRange: [0, 500],
|
||||
outputRange: [0, 500],
|
||||
extrapolate: Extrapolate.CLAMP
|
||||
}), [translateY.current]);
|
||||
|
||||
extrapolate: Extrapolate.CLAMP,
|
||||
}),
|
||||
[translateY.current],
|
||||
);
|
||||
|
||||
const _animatedStyle = {
|
||||
transform: [
|
||||
{
|
||||
translateY: consY,
|
||||
},
|
||||
]
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
const _onPanHandlerStateChange = (e: HandlerStateChangeEvent<PanGestureHandlerEventPayload>) => {
|
||||
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 (
|
||||
<PanGestureHandler onGestureEvent={_onGestureEvent}
|
||||
<PanGestureHandler
|
||||
onGestureEvent={_onGestureEvent}
|
||||
onHandlerStateChange={_onPanHandlerStateChange}
|
||||
onEnded={_onPanEnded}>
|
||||
onEnded={_onPanEnded}
|
||||
>
|
||||
<Animated.View style={_animatedStyle}>
|
||||
<View onLayout={(e) => {
|
||||
<View
|
||||
onLayout={(e) => {
|
||||
extensionHeight.current = e.nativeEvent.layout.height;
|
||||
console.log('extension height', extensionHeight.current)
|
||||
|
||||
}} style={styles.dropShadow}>
|
||||
console.log('extension height', extensionHeight.current);
|
||||
}}
|
||||
style={styles.dropShadow}
|
||||
>
|
||||
{isExtensionVisible && <View style={styles.indicator} />}
|
||||
<UploadsGalleryModal
|
||||
ref={uploadsGalleryModalRef}
|
||||
@ -184,23 +191,25 @@ export const EditorToolbar = ({
|
||||
username={currentAccount.username}
|
||||
hideToolbarExtension={_hideExtension}
|
||||
handleMediaInsert={handleMediaInsert}
|
||||
setIsUploading={setIsUploading} />
|
||||
setIsUploading={setIsUploading}
|
||||
/>
|
||||
</View>
|
||||
</Animated.View>
|
||||
</PanGestureHandler>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
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 (
|
||||
<View style={_containerStyle}>
|
||||
|
||||
{_renderExtension()}
|
||||
|
||||
{!isPreviewActive && (
|
||||
@ -220,10 +229,14 @@ export const EditorToolbar = ({
|
||||
iconStyle={styles.icon}
|
||||
iconType="FontAwesome"
|
||||
name="link"
|
||||
onPress={() => { handleOnAddLinkPress && handleOnAddLinkPress() }}
|
||||
onPress={() => {
|
||||
handleOnAddLinkPress && handleOnAddLinkPress();
|
||||
}}
|
||||
/>
|
||||
<IconButton
|
||||
onPress={() => { handleShowSnippets && handleShowSnippets() }}
|
||||
onPress={() => {
|
||||
handleShowSnippets && handleShowSnippets();
|
||||
}}
|
||||
style={styles.rightIcons}
|
||||
size={20}
|
||||
iconStyle={styles.icon}
|
||||
@ -240,7 +253,9 @@ export const EditorToolbar = ({
|
||||
/>
|
||||
<View style={styles.clearButtonWrapper}>
|
||||
<IconButton
|
||||
onPress={() => { handleOnClearPress && handleOnClearPress() }}
|
||||
onPress={() => {
|
||||
handleOnClearPress && handleOnClearPress();
|
||||
}}
|
||||
size={20}
|
||||
iconStyle={styles.clearIcon}
|
||||
iconType="FontAwesome"
|
||||
@ -251,9 +266,6 @@ export const EditorToolbar = ({
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
</View>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -1,42 +1,42 @@
|
||||
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[]
|
||||
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
|
||||
|
||||
const imagePrefix = '!';
|
||||
const placeholderPrefix = 'Uploading... '
|
||||
const placeholderPrefix = 'Uploading... ';
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
end: newIndex,
|
||||
};
|
||||
};
|
||||
|
||||
const _replaceFormatedString = (placeholder: string, url: string) => {
|
||||
const replaceStr = `(${placeholder})`;
|
||||
@ -45,38 +45,34 @@ export default async ({ text, selection, setTextAndSelection, items }: Args) =>
|
||||
newText = newText.replace(replaceStr, `(${url})`);
|
||||
|
||||
if (newSelection.start >= endingIndex) {
|
||||
const lengthDiff = url.length - placeholder.length
|
||||
const lengthDiff = url.length - placeholder.length;
|
||||
newSelection = {
|
||||
start: newSelection.start + lengthDiff,
|
||||
end: newSelection.end + lengthDiff
|
||||
end: newSelection.end + lengthDiff,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const _removeFormatedString = (placeholder) => {
|
||||
const formatedText = `${imagePrefix}[](${placeholder})`
|
||||
const formatedText = `${imagePrefix}[](${placeholder})`;
|
||||
const formatedTextIndex = newText.indexOf(formatedText);
|
||||
newText = newText.replace(formatedText, '')
|
||||
newText = newText.replace(formatedText, '');
|
||||
|
||||
if (newSelection.start > formatedTextIndex) {
|
||||
newSelection = {
|
||||
start: newSelection.start - formatedText.length,
|
||||
end: newSelection.end - formatedText.length
|
||||
}
|
||||
}
|
||||
end: newSelection.end - formatedText.length,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
items.forEach(item => {
|
||||
|
||||
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)
|
||||
_insertFormatedString(item.text, _placeholder);
|
||||
break;
|
||||
|
||||
case MediaInsertStatus.READY: //means url is ready but filename may be available
|
||||
@ -100,9 +96,7 @@ export default async ({ text, selection, setTextAndSelection, items }: Args) =>
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
setTextAndSelection({ text: newText, selection: newSelection });
|
||||
};
|
||||
|
@ -1,6 +1,6 @@
|
||||
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,
|
||||
|
@ -1,10 +1,14 @@
|
||||
import { extractWordAtIndex } from '../../../../utils/editor';
|
||||
import {replaceBetween } from './utils';
|
||||
import { replaceBetween } from './utils';
|
||||
|
||||
export default async ({ text, selection, setTextAndSelection, username}) => {
|
||||
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 _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 });
|
||||
|
@ -1,82 +1,93 @@
|
||||
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) => {
|
||||
|
||||
const [searchedUsers, setSearchedUsers] = useState([])
|
||||
export const UsernameAutofillBar = ({ text, selection, onApplyUsername }: Props) => {
|
||||
const [searchedUsers, setSearchedUsers] = useState([]);
|
||||
const [query, setQuery] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (selection.start === selection.end && text) {
|
||||
_processTextForSearch(text, selection.start);
|
||||
}
|
||||
}, [text, selection])
|
||||
}, [text, selection]);
|
||||
|
||||
|
||||
const _processTextForSearch = useCallback(debounce((text:string, index:number) => {
|
||||
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('')
|
||||
setQuery('');
|
||||
_handleUserSearch.cancel();
|
||||
}
|
||||
}, 300, {leading:true}),[]);
|
||||
},
|
||||
300,
|
||||
{ leading: true },
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
|
||||
const _handleUserSearch = useCallback(debounce(async (username) => {
|
||||
if(query !== username){
|
||||
const _handleUserSearch = useCallback(
|
||||
debounce(
|
||||
async (username) => {
|
||||
if (query !== username) {
|
||||
let users = [];
|
||||
if (username) {
|
||||
setQuery(username)
|
||||
setQuery(username);
|
||||
users = await lookupAccounts(username);
|
||||
console.log('result users for', username, users);
|
||||
}
|
||||
setSearchedUsers(users);
|
||||
}
|
||||
|
||||
}, 200, {leading:true}), []);
|
||||
|
||||
200,
|
||||
{ leading: true },
|
||||
),
|
||||
|
||||
);
|
||||
|
||||
const _onUserSelect = (username) => {
|
||||
onApplyUsername(username)
|
||||
onApplyUsername(username);
|
||||
setSearchedUsers([]);
|
||||
setQuery('')
|
||||
setQuery('');
|
||||
};
|
||||
|
||||
if(!searchedUsers || searchedUsers.length === 0 || query === ''){
|
||||
if (!searchedUsers || searchedUsers.length === 0 || query === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _renderItem = ({item}:{item:string}) => {
|
||||
|
||||
const _renderItem = ({ item }: { item: string }) => {
|
||||
const username = item;
|
||||
return (
|
||||
<TouchableOpacity onPress={()=>{_onUserSelect(username)}}>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
_onUserSelect(username);
|
||||
}}
|
||||
>
|
||||
<View style={styles.userBubble}>
|
||||
<UserAvatar username={username}/>
|
||||
<UserAvatar username={username} />
|
||||
<Text style={styles.userBubbleText}>{username}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.searchAccountsContainer}>
|
||||
@ -86,8 +97,8 @@ export const UsernameAutofillBar = ({text, selection, onApplyUsername}:Props) =>
|
||||
keyboardShouldPersistTaps="always"
|
||||
showsHorizontalScrollIndicator={false}
|
||||
renderItem={_renderItem}
|
||||
keyExtractor={(item)=>`searched-user-${item}`}
|
||||
keyExtractor={(item) => `searched-user-${item}`}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -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',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
|
@ -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,23 +189,26 @@ const MarkdownEditorView = ({
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const _debouncedOnTextChange = useCallback(debounce(() => {
|
||||
console.log("setting is editing to", false)
|
||||
setIsEditing(false)
|
||||
const urls = extractImageUrls({ body: bodyText })
|
||||
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), [])
|
||||
}, 500),
|
||||
[],
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const _changeText = useCallback((input) => {
|
||||
const _changeText = useCallback(
|
||||
(input) => {
|
||||
bodyText = input;
|
||||
|
||||
if (!isEditing) {
|
||||
console.log('force setting is editing to true', true)
|
||||
setIsEditing(true)
|
||||
console.log('force setting is editing to true', true);
|
||||
setIsEditing(true);
|
||||
}
|
||||
|
||||
_debouncedOnTextChange();
|
||||
@ -218,8 +217,9 @@ const MarkdownEditorView = ({
|
||||
if (onChange) {
|
||||
onChange(input);
|
||||
}
|
||||
}, [isEditing]);
|
||||
|
||||
},
|
||||
[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 && <SummaryArea summary={headerText} />}
|
||||
{!isReply && (
|
||||
@ -421,14 +415,20 @@ const MarkdownEditorView = ({
|
||||
</>
|
||||
);
|
||||
|
||||
const _editorWithScroll = <ScrollView style={styles.container}>{_renderEditor(false)}</ScrollView>;
|
||||
const _editorWithScroll = (
|
||||
<ScrollView style={styles.container}>{_renderEditor(false)}</ScrollView>
|
||||
);
|
||||
const _editorWithoutScroll = <View style={styles.container}>{_renderEditor(true)}</View>;
|
||||
|
||||
const _renderContent = () => {
|
||||
const _innerContent = (
|
||||
<>
|
||||
{isAndroidOreo() ? _editorWithoutScroll : _editorWithScroll}
|
||||
<UsernameAutofillBar text={bodyText} selection={bodySelection} onApplyUsername={_onApplyUsername} />
|
||||
<UsernameAutofillBar
|
||||
text={bodyText}
|
||||
selection={bodySelection}
|
||||
onApplyUsername={_onApplyUsername}
|
||||
/>
|
||||
{_renderFloatingDraftButton()}
|
||||
|
||||
<EditorToolbar
|
||||
@ -445,11 +445,10 @@ const MarkdownEditorView = ({
|
||||
text: bodyText,
|
||||
selection: bodySelection,
|
||||
setTextAndSelection: _setTextAndSelection,
|
||||
item
|
||||
})
|
||||
item,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
</>
|
||||
);
|
||||
|
||||
@ -480,8 +479,6 @@ const MarkdownEditorView = ({
|
||||
<SnippetsModal handleOnSelect={_handleOnSnippetReceived} />
|
||||
</Modal>
|
||||
|
||||
|
||||
|
||||
<InsertLinkModal
|
||||
ref={insertLinkModalRef}
|
||||
handleOnInsertLink={_handleInsertLink}
|
||||
|
@ -1,12 +1,10 @@
|
||||
import {ViewStyle } from 'react-native';
|
||||
import { ViewStyle } from 'react-native';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent:"flex-end",
|
||||
justifyContent: 'flex-end',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.2)',
|
||||
} as ViewStyle,
|
||||
|
||||
})
|
||||
});
|
||||
|
@ -1,17 +1,16 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { View as AnimatedView } from 'react-native-animatable'
|
||||
import { View as AnimatedView } from 'react-native-animatable';
|
||||
import { Portal } from 'react-native-portalize';
|
||||
import styles from '../children/inputSupportModal.styles';
|
||||
import { KeyboardAvoidingView, Platform, View } from 'react-native';
|
||||
import styles from '../children/inputSupportModal.styles';
|
||||
|
||||
export interface InputSupportModalProps {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
children?: any
|
||||
children?: any;
|
||||
}
|
||||
|
||||
export const InputSupportModal = ({ children, visible, onClose }: InputSupportModalProps, ref) => {
|
||||
|
||||
const container = useRef<AnimatedView>(null);
|
||||
const innerContainer = useRef<AnimatedView>(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 && (
|
||||
return (
|
||||
showModal && (
|
||||
<Portal>
|
||||
|
||||
<AnimatedView
|
||||
ref={container}
|
||||
animation='fadeIn'
|
||||
duration={300}
|
||||
style={styles.container} >
|
||||
|
||||
<AnimatedView ref={container} animation="fadeIn" duration={300} style={styles.container}>
|
||||
<AnimatedView
|
||||
ref={innerContainer}
|
||||
style={{ flex: 1 }}
|
||||
animation='slideInUp'
|
||||
duration={300}>
|
||||
animation="slideInUp"
|
||||
duration={300}
|
||||
>
|
||||
<View style={{ flex: 1 }} onTouchEnd={onClose} />
|
||||
|
||||
<View
|
||||
style={{ flex: 1 }}
|
||||
onTouchEnd={onClose} />
|
||||
|
||||
{
|
||||
Platform.select({
|
||||
{Platform.select({
|
||||
ios: (
|
||||
<KeyboardAvoidingView behavior="padding" style={{}}>
|
||||
{children}
|
||||
</KeyboardAvoidingView>
|
||||
),
|
||||
android: <View>{children}</View>,
|
||||
})
|
||||
}
|
||||
})}
|
||||
</AnimatedView>
|
||||
</AnimatedView>
|
||||
</Portal>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
@ -290,7 +290,7 @@ class PostDropdownContainer extends PureComponent {
|
||||
buttons: [
|
||||
{
|
||||
text: intl.formatMessage({ id: 'alert.cancel' }),
|
||||
onPress: () => { },
|
||||
onPress: () => {},
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage({ id: 'alert.confirm' }),
|
||||
@ -337,9 +337,8 @@ class PostDropdownContainer extends PureComponent {
|
||||
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) => (
|
||||
<PostDropdownContainer {...props} {...mapQueriesToProps()} />)))
|
||||
export default withNavigation(
|
||||
connect(mapStateToProps)(
|
||||
injectIntl((props) => <PostDropdownContainer {...props} {...mapQueriesToProps()} />),
|
||||
),
|
||||
);
|
||||
|
@ -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
|
||||
@ -130,10 +127,9 @@ 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 (
|
||||
<Fragment>
|
||||
<Modal key={`mkey-${created.toString()}`} visible={isImageModalOpen} transparent={true}>
|
||||
<ImageViewer
|
||||
imageUrls={postImages.map((url)=>({url}))}
|
||||
imageUrls={postImages.map((url) => ({ url }))}
|
||||
enableSwipeDown
|
||||
onCancel={() => setIsImageModalOpen(false)}
|
||||
onClick={() => setIsImageModalOpen(false)}
|
||||
@ -339,7 +334,6 @@ const CommentBody = ({
|
||||
/>
|
||||
</View>
|
||||
</LongPressGestureHandler>
|
||||
|
||||
) : (
|
||||
<TextButton
|
||||
style={styles.revealButton}
|
||||
@ -371,4 +365,3 @@ const CommentBody = ({
|
||||
};
|
||||
|
||||
export default CommentBody;
|
||||
|
||||
|
@ -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<string[]>([]);
|
||||
|
||||
//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);
|
||||
|
@ -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:{
|
||||
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,
|
||||
});
|
||||
|
||||
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
@ -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<any> {
|
||||
promotedPosts:Array<any>;
|
||||
isFeedScreen:boolean;
|
||||
onLoadPosts?:(shouldReset:boolean)=>void;
|
||||
isLoading:boolean;
|
||||
isRefreshing:boolean;
|
||||
pageType:'main'|'profile'|'ownProfile'|'community';
|
||||
showQuickReplyModal:(post:any)=>void;
|
||||
promotedPosts: Array<any>;
|
||||
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,7 +32,9 @@ const postsListContainer = ({
|
||||
pageType,
|
||||
showQuickReplyModal,
|
||||
...props
|
||||
}:postsListContainerProps, ref) => {
|
||||
}: postsListContainerProps,
|
||||
ref,
|
||||
) => {
|
||||
|
||||
const flatListRef = useRef(null);
|
||||
|
||||
@ -39,16 +42,12 @@ const postsListContainer = ({
|
||||
|
||||
const isHideImages = useSelector((state) => state.application.hidePostsThumbnails);
|
||||
const posts = useSelector((state) => {
|
||||
return isFeedScreen
|
||||
? state.posts.feedPosts
|
||||
: state.posts.otherPosts
|
||||
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
|
||||
return isFeedScreen ? state.posts.feedScrollPosition : state.posts.otherScrollPosition;
|
||||
});
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
@ -58,38 +57,36 @@ const postsListContainer = ({
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Scroll Position: ", scrollPosition)
|
||||
if(posts && posts.length == 0){
|
||||
console.log('Scroll Position: ', scrollPosition);
|
||||
if (posts && posts.length == 0) {
|
||||
flatListRef.current?.scrollToOffset({
|
||||
offset: 0,
|
||||
animated: false
|
||||
animated: false,
|
||||
});
|
||||
}
|
||||
|
||||
}, [posts])
|
||||
}, [posts]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Scroll Position: ", scrollPosition)
|
||||
console.log('Scroll Position: ', scrollPosition);
|
||||
flatListRef.current?.scrollToOffset({
|
||||
offset: (posts && posts.length == 0) ? 0 : scrollPosition,
|
||||
animated: false
|
||||
offset: posts && posts.length == 0 ? 0 : scrollPosition,
|
||||
animated: false,
|
||||
});
|
||||
|
||||
}, [scrollPosition])
|
||||
}, [scrollPosition]);
|
||||
|
||||
const _setImageHeightInMap = (mapKey:string, height:number) => {
|
||||
if(mapKey && height){
|
||||
const _setImageHeightInMap = (mapKey: string, height: number) => {
|
||||
if (mapKey && height) {
|
||||
setImageHeights(imageHeights.set(mapKey, height));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
const _renderFooter = () => {
|
||||
if (isLoading && !isRefreshing) {
|
||||
return (
|
||||
<View style={styles.flatlistFooter}>
|
||||
<ActivityIndicator animating size="large" color={'#2e3d51'} />
|
||||
<ActivityIndicator animating size="large" color="#2e3d51" />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -104,8 +101,7 @@ const postsListContainer = ({
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const _renderItem = ({ item, index }:{item:any, index:number}) => {
|
||||
const _renderItem = ({ item, index }: { item: any; index: number }) => {
|
||||
const e = [] as any;
|
||||
|
||||
if (index % 3 === 0) {
|
||||
@ -114,7 +110,11 @@ const postsListContainer = ({
|
||||
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) {
|
||||
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;
|
||||
@ -127,10 +127,10 @@ const postsListContainer = ({
|
||||
isHideImage={isHideImages}
|
||||
imageHeight={imgHeight}
|
||||
pageType={pageType}
|
||||
setImageHeight = {_setImageHeightInMap}
|
||||
setImageHeight={_setImageHeightInMap}
|
||||
showQuickReplyModal={showQuickReplyModal}
|
||||
mutes={mutes}
|
||||
/>
|
||||
/>,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -140,7 +140,7 @@ const postsListContainer = ({
|
||||
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 imgHeight = imageHeights.get(localId);
|
||||
|
||||
e.push(
|
||||
<PostCard
|
||||
@ -148,7 +148,7 @@ const postsListContainer = ({
|
||||
content={item}
|
||||
isHideImage={isHideImages}
|
||||
imageHeight={imgHeight}
|
||||
setImageHeight = {_setImageHeightInMap}
|
||||
setImageHeight={_setImageHeightInMap}
|
||||
pageType={pageType}
|
||||
showQuickReplyModal={showQuickReplyModal}
|
||||
mutes={mutes}
|
||||
@ -181,7 +181,11 @@ const postsListContainer = ({
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={isRefreshing}
|
||||
onRefresh={()=>{if(onLoadPosts){onLoadPosts(true)}}}
|
||||
onRefresh={() => {
|
||||
if (onLoadPosts) {
|
||||
onLoadPosts(true);
|
||||
}
|
||||
}}
|
||||
progressBackgroundColor="#357CE6"
|
||||
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
|
||||
titleColor="#fff"
|
||||
@ -192,8 +196,8 @@ const postsListContainer = ({
|
||||
/>
|
||||
)}
|
||||
</ThemeContainer>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default forwardRef(postsListContainer);
|
||||
|
@ -1,25 +1,30 @@
|
||||
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 isHideImage = useAppSelector(state => state.application.hidePostsThumbnails);
|
||||
const isHideImage = useAppSelector((state) => state.application.hidePostsThumbnails);
|
||||
|
||||
const [data, setData] = useState([]);
|
||||
const [lastAuthor, setLastAuthor] = useState('');
|
||||
@ -28,58 +33,55 @@ const CommentsTabContent = ({isOwnProfile, username, type, onScroll, selectedUse
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [noMore, setNoMore] = useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if(selectedUser){
|
||||
if (selectedUser) {
|
||||
_fetchData();
|
||||
}
|
||||
}, [selectedUser])
|
||||
}, [selectedUser]);
|
||||
|
||||
|
||||
const _fetchData = async ({refresh}:{refresh?:boolean} = {}) => {
|
||||
if(loading || (!refresh && noMore)){
|
||||
const _fetchData = async ({ refresh }: { refresh?: boolean } = {}) => {
|
||||
if (loading || (!refresh && noMore)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
if(refresh){
|
||||
if (refresh) {
|
||||
setRefreshing(true);
|
||||
}
|
||||
|
||||
const query:any = {
|
||||
account:username,
|
||||
const query: any = {
|
||||
account: username,
|
||||
start_author: refresh ? '' : lastAuthor,
|
||||
start_permlink: refresh ? '' : lastPermlink,
|
||||
limit:10,
|
||||
observer:'',
|
||||
sort:type
|
||||
limit: 10,
|
||||
observer: '',
|
||||
sort: type,
|
||||
};
|
||||
|
||||
const result = await getAccountPosts(query)
|
||||
let _comments:any[] = refresh ? result : unionBy(data, result, 'permlink');
|
||||
const result = await getAccountPosts(query);
|
||||
let _comments: any[] = refresh ? result : unionBy(data, result, 'permlink');
|
||||
|
||||
if(Array.isArray(_comments)){
|
||||
if (Array.isArray(_comments)) {
|
||||
setData(_comments);
|
||||
if(_comments.length > 0){
|
||||
setLastAuthor(_comments[_comments.lastIndex].author)
|
||||
setLastPermlink(_comments[_comments.lastIndex].permlink)
|
||||
if (_comments.length > 0) {
|
||||
setLastAuthor(_comments[_comments.lastIndex].author);
|
||||
setLastPermlink(_comments[_comments.lastIndex].permlink);
|
||||
}
|
||||
if(result.length == 0){
|
||||
if (result.length == 0) {
|
||||
setNoMore(true);
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
setData([]);
|
||||
setNoMore(true);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
setRefreshing(false);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
const _renderListEmpty = () => {
|
||||
if(loading){
|
||||
return null
|
||||
if (loading) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<NoPost
|
||||
@ -91,39 +93,34 @@ const CommentsTabContent = ({isOwnProfile, username, type, onScroll, selectedUse
|
||||
id: 'profile.login_to_see',
|
||||
})}
|
||||
/>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const _renderListFooter = () => {
|
||||
return (
|
||||
<View style={styles.commentsListFooter}>
|
||||
{loading && (
|
||||
<ActivityIndicator size='large'/>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
<View style={styles.commentsListFooter}>{loading && <ActivityIndicator size="large" />}</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<View key="profile.comments" style={styles.commentsTabBar}>
|
||||
<Comments
|
||||
comments={data}
|
||||
fetchPost={()=>{}}
|
||||
fetchPost={() => {}}
|
||||
isOwnProfile={isOwnProfile}
|
||||
isHideImage={isHideImage}
|
||||
flatListProps={{
|
||||
onEndReached:_fetchData,
|
||||
onScroll:onScroll,
|
||||
ListEmptyComponent:_renderListEmpty,
|
||||
ListFooterComponent:_renderListFooter,
|
||||
onEndReachedThreshold:1,
|
||||
refreshControl:(
|
||||
onEndReached: _fetchData,
|
||||
onScroll: onScroll,
|
||||
ListEmptyComponent: _renderListEmpty,
|
||||
ListFooterComponent: _renderListFooter,
|
||||
onEndReachedThreshold: 1,
|
||||
refreshControl: (
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={()=>_fetchData({refresh:true})}
|
||||
onRefresh={() => _fetchData({ refresh: true })}
|
||||
/>
|
||||
)
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
|
@ -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,17 +47,14 @@ const ProfileEditFormView = ({
|
||||
showImageUploadActions,
|
||||
saveEnabled,
|
||||
...props
|
||||
}:ProfileEditFormProps) => (
|
||||
|
||||
}: ProfileEditFormProps) => (
|
||||
<View style={styles.container}>
|
||||
|
||||
<KeyboardAwareScrollView
|
||||
enableAutoAutomaticScroll={Platform.OS === 'ios'}
|
||||
contentContainerStyle={styles.contentContainer}
|
||||
enableOnAndroid={true}
|
||||
>
|
||||
<TouchableOpacity style={styles.coverImgWrapper} onPress={showImageUploadActions}>
|
||||
|
||||
<FastImage
|
||||
style={styles.coverImg}
|
||||
source={
|
||||
@ -69,16 +65,13 @@ const ProfileEditFormView = ({
|
||||
: LIGHT_COVER_IMAGE
|
||||
}
|
||||
/>
|
||||
{
|
||||
isUploading && (
|
||||
{isUploading && (
|
||||
<ActivityIndicator
|
||||
style={styles.activityIndicator}
|
||||
color={EStyleSheet.value('$white')}
|
||||
size='large'
|
||||
size="large"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
)}
|
||||
|
||||
<IconButton
|
||||
iconStyle={styles.addIcon}
|
||||
@ -115,7 +108,7 @@ const ProfileEditFormView = ({
|
||||
{saveEnabled && (
|
||||
<AnimatedView style={styles.floatingContainer} animation="bounceInRight">
|
||||
<MainButton
|
||||
style={{ width: isLoading ? null : 120, marginBottom:24, alignSelf:'flex-end' }}
|
||||
style={{ width: isLoading ? null : 120, marginBottom: 24, alignSelf: 'flex-end' }}
|
||||
onPress={handleOnSubmit}
|
||||
iconName="save"
|
||||
iconType="MaterialIcons"
|
||||
@ -125,8 +118,6 @@ const ProfileEditFormView = ({
|
||||
/>
|
||||
</AnimatedView>
|
||||
)}
|
||||
|
||||
|
||||
</View>
|
||||
);
|
||||
|
||||
|
@ -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 && (
|
||||
<View style={styles.activityIndicatorContainer}>
|
||||
<ActivityIndicator color={'white'} style={styles.activityIndicator} />
|
||||
<ActivityIndicator color="white" style={styles.activityIndicator} />
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
@ -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,10 +36,8 @@ export interface QuickReplyModalContentProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const QuickReplyModalContent = forwardRef(({
|
||||
selectedPost,
|
||||
onClose,
|
||||
}: QuickReplyModalContentProps, ref) => {
|
||||
export const QuickReplyModalContent = forwardRef(
|
||||
({ selectedPost, onClose }: QuickReplyModalContentProps, ref) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const userActivityMutation = useUserActivityMutation();
|
||||
@ -47,24 +51,22 @@ export const QuickReplyModalContent = forwardRef(({
|
||||
const [commentValue, setCommentValue] = useState('');
|
||||
const [isSending, setIsSending] = useState(false);
|
||||
|
||||
|
||||
const headerText =
|
||||
selectedPost && (selectedPost.summary || postBodySummary(selectedPost, 150, Platform.OS as any));
|
||||
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 = ''
|
||||
let _value = '';
|
||||
if (drafts.has(draftId) && currentAccount.name === drafts.get(draftId).author) {
|
||||
const quickComment: Draft = drafts.get(draftId);
|
||||
_value = quickComment.body;
|
||||
@ -72,34 +74,28 @@ export const QuickReplyModalContent = forwardRef(({
|
||||
|
||||
if (inputRef.current) {
|
||||
inputRef.current.setNativeProps({
|
||||
text: _value
|
||||
})
|
||||
setCommentValue(_value)
|
||||
text: _value,
|
||||
});
|
||||
setCommentValue(_value);
|
||||
}
|
||||
|
||||
}, [selectedPost]);
|
||||
|
||||
|
||||
|
||||
// add quick comment value into cache
|
||||
const _addQuickCommentIntoCache = (value = commentValue) => {
|
||||
|
||||
const quickCommentDraftData: Draft = {
|
||||
author: currentAccount.name,
|
||||
body: value
|
||||
body: value,
|
||||
};
|
||||
|
||||
//add quick comment cache entry
|
||||
dispatch(updateDraftCache(draftId, quickCommentDraftData));
|
||||
};
|
||||
|
||||
|
||||
// handle close press
|
||||
const _handleClosePress = () => {
|
||||
onClose()
|
||||
onClose();
|
||||
};
|
||||
|
||||
|
||||
// navigate to post on summary press
|
||||
const _handleOnSummaryPress = () => {
|
||||
Keyboard.dismiss();
|
||||
@ -113,10 +109,8 @@ export const QuickReplyModalContent = forwardRef(({
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// handle submit reply
|
||||
const _submitReply = async () => {
|
||||
|
||||
if (!commentValue) {
|
||||
return;
|
||||
}
|
||||
@ -153,16 +147,16 @@ export const QuickReplyModalContent = forwardRef(({
|
||||
)
|
||||
.then((response) => {
|
||||
userActivityMutation.mutate({
|
||||
pointsTy:PointActivityIds.COMMENT,
|
||||
transactionId:response.id
|
||||
})
|
||||
pointsTy: PointActivityIds.COMMENT,
|
||||
transactionId: response.id,
|
||||
});
|
||||
setIsSending(false);
|
||||
setCommentValue('');
|
||||
|
||||
if(inputRef.current){
|
||||
if (inputRef.current) {
|
||||
inputRef.current.setNativeProps({
|
||||
text: ''
|
||||
})
|
||||
text: '',
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(
|
||||
@ -207,10 +201,8 @@ export const QuickReplyModalContent = forwardRef(({
|
||||
error.message || JSON.stringify(error),
|
||||
);
|
||||
|
||||
|
||||
setIsSending(false);
|
||||
_addQuickCommentIntoCache(); //add comment value into cache if there is error while posting comment
|
||||
|
||||
});
|
||||
console.log('status : ', status);
|
||||
}
|
||||
@ -232,7 +224,6 @@ export const QuickReplyModalContent = forwardRef(({
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//REMOVED FOR TESTING, CAN BE PUT BACK IF APP STILL CRASHES
|
||||
// const _deboucedCacheUpdate = useCallback(debounce(_addQuickCommentIntoCache, 500), [])
|
||||
|
||||
@ -240,13 +231,10 @@ export const QuickReplyModalContent = forwardRef(({
|
||||
setCommentValue(value);
|
||||
//REMOVED FOR TESTING, CAN BE PUT BACK IF APP STILL CRASHES
|
||||
// _deboucedCacheUpdate(value)
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
//VIEW_RENDERERS
|
||||
|
||||
|
||||
const _renderSummary = () => (
|
||||
<TouchableOpacity onPress={() => _handleOnSummaryPress()}>
|
||||
<Text numberOfLines={2} style={styles.summaryStyle}>
|
||||
@ -296,8 +284,6 @@ export const QuickReplyModalContent = forwardRef(({
|
||||
</View>
|
||||
);
|
||||
|
||||
|
||||
|
||||
const _renderContent = (
|
||||
<View style={styles.modalContainer}>
|
||||
{_renderSummary()}
|
||||
@ -322,7 +308,8 @@ export const QuickReplyModalContent = forwardRef(({
|
||||
{_renderReplyBtn()}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
);
|
||||
|
||||
return _renderContent
|
||||
});
|
||||
return _renderContent;
|
||||
},
|
||||
);
|
||||
|
@ -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',
|
||||
|
@ -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 (
|
||||
<InputSupportModal
|
||||
visible={replyModalVisible && !!replyModalPost}
|
||||
onClose={_onClose}
|
||||
>
|
||||
<InputSupportModal visible={replyModalVisible && !!replyModalPost} onClose={_onClose}>
|
||||
<QuickReplyModalContent
|
||||
ref={modalContentRef}
|
||||
selectedPost={replyModalPost}
|
||||
onClose={_onClose}
|
||||
/>
|
||||
</InputSupportModal>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,22 +1,27 @@
|
||||
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){
|
||||
export const SimpleChart = ({
|
||||
data,
|
||||
baseWidth,
|
||||
chartHeight,
|
||||
showLine,
|
||||
showLabels = false,
|
||||
}: CoinChartProps) => {
|
||||
if (!data || !data.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _chartWidth = baseWidth + baseWidth/(data.length -1)
|
||||
const _chartWidth = baseWidth + baseWidth / (data.length - 1);
|
||||
const _chartBackgroundColor = EStyleSheet.value('$primaryLightBackground');
|
||||
return (
|
||||
<LineChart
|
||||
@ -24,8 +29,8 @@ export const SimpleChart = ({data, baseWidth, chartHeight, showLine, showLabels
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
data
|
||||
}
|
||||
data,
|
||||
},
|
||||
],
|
||||
}}
|
||||
width={_chartWidth} // from react-native
|
||||
@ -36,15 +41,14 @@ export const SimpleChart = ({data, baseWidth, chartHeight, showLine, showLabels
|
||||
withDots={false}
|
||||
withInnerLines={false}
|
||||
chartConfig={{
|
||||
backgroundColor:_chartBackgroundColor,
|
||||
backgroundColor: _chartBackgroundColor,
|
||||
backgroundGradientFrom: _chartBackgroundColor,
|
||||
backgroundGradientTo: _chartBackgroundColor,
|
||||
fillShadowGradient: EStyleSheet.value('$chartBlue'),
|
||||
fillShadowGradientOpacity:0.8,
|
||||
labelColor:() => EStyleSheet.value('$primaryDarkText'),
|
||||
color: () => showLine?EStyleSheet.value('$chartBlue'):'transparent',
|
||||
fillShadowGradientOpacity: 0.8,
|
||||
labelColor: () => EStyleSheet.value('$primaryDarkText'),
|
||||
color: () => (showLine ? EStyleSheet.value('$chartBlue') : 'transparent'),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
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;
|
||||
|
||||
@ -20,16 +20,15 @@ export const loadPosts = async ({
|
||||
pageType,
|
||||
tag,
|
||||
nsfw,
|
||||
|
||||
}:LoadPostsOptions) => {
|
||||
}: LoadPostsOptions) => {
|
||||
let filter = filterKey;
|
||||
|
||||
//match filter with api if is friends
|
||||
if(filter === 'friends'){
|
||||
if (filter === 'friends') {
|
||||
filter = 'feed';
|
||||
}
|
||||
|
||||
const {isLoading, startPermlink, startAuthor} = tabMeta;
|
||||
const { isLoading, startPermlink, startAuthor } = tabMeta;
|
||||
|
||||
//reject update if already loading
|
||||
if (
|
||||
@ -45,17 +44,17 @@ export const loadPosts = async ({
|
||||
if (!isConnected && (refreshing || isLoading)) {
|
||||
setTabMeta({
|
||||
...tabMeta,
|
||||
isLoading:false,
|
||||
isRefreshing:false,
|
||||
})
|
||||
isLoading: false,
|
||||
isRefreshing: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setTabMeta({
|
||||
...tabMeta,
|
||||
isLoading:true,
|
||||
isRefreshing:refreshing,
|
||||
})
|
||||
isLoading: true,
|
||||
isRefreshing: refreshing,
|
||||
});
|
||||
|
||||
let options = {} as any;
|
||||
const limit = isLatestPostsCheck ? 5 : POSTS_FETCH_COUNT;
|
||||
@ -86,7 +85,10 @@ export const loadPosts = async ({
|
||||
sort: filter,
|
||||
};
|
||||
|
||||
if ((pageType === 'profile' || pageType === 'ownProfile') && (filter === 'feed' || filter === 'posts')) {
|
||||
if (
|
||||
(pageType === 'profile' || pageType === 'ownProfile') &&
|
||||
(filter === 'feed' || filter === 'posts')
|
||||
) {
|
||||
options.sort = 'posts';
|
||||
}
|
||||
}
|
||||
@ -99,7 +101,6 @@ export const loadPosts = async ({
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
if (startAuthor && startPermlink && !refreshing && !isLatestPostsCheck) {
|
||||
options.start_author = startAuthor;
|
||||
options.start_permlink = startPermlink;
|
||||
@ -107,86 +108,85 @@ export const loadPosts = async ({
|
||||
|
||||
try {
|
||||
//fetching posts
|
||||
const result:any[] = await func(options, feedUsername, nsfw);
|
||||
const result: any[] = await func(options, feedUsername, nsfw);
|
||||
|
||||
if(result.length > 0){
|
||||
if(filter === 'reblogs'){
|
||||
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){
|
||||
if ((pageType === 'profile' || pageType === 'ownProfile') && pinnedPermlink) {
|
||||
let pinnedIndex = -1;
|
||||
result.forEach((post, index)=>{
|
||||
if(post.author === feedUsername && post.permlink === pinnedPermlink){
|
||||
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 (filter === 'feed') {
|
||||
filter = 'friends';
|
||||
}
|
||||
|
||||
// cacheDispatch(updateFilterCache(filter, result, refreshing))
|
||||
setTabMeta({
|
||||
...tabMeta,
|
||||
isLoading:false,
|
||||
isRefreshing:false,
|
||||
})
|
||||
isLoading: false,
|
||||
isRefreshing: false,
|
||||
});
|
||||
|
||||
const retData = {
|
||||
latestPosts:null,
|
||||
updatedPosts:null
|
||||
}
|
||||
latestPosts: null,
|
||||
updatedPosts: null,
|
||||
};
|
||||
|
||||
if(isLatestPostsCheck){
|
||||
if (isLatestPostsCheck) {
|
||||
const latestPosts = filterLatestPosts(result, prevPosts.slice(0, 5));
|
||||
retData.latestPosts = latestPosts
|
||||
}else{
|
||||
retData.latestPosts = latestPosts;
|
||||
} else {
|
||||
const updatedPosts = getUpdatedPosts(
|
||||
startAuthor && startPermlink ? prevPosts:[],
|
||||
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){
|
||||
if (
|
||||
retData.updatedPosts &&
|
||||
pinnedPermlink &&
|
||||
retData.updatedPosts[0].permlink !== pinnedPermlink
|
||||
) {
|
||||
const pinnedPost = await getPost(feedUsername, pinnedPermlink);
|
||||
pinnedPost.stats = {is_pinned_blog:true, ...pinnedPost.stats};
|
||||
pinnedPost.stats = { is_pinned_blog: true, ...pinnedPost.stats };
|
||||
retData.updatedPosts = [pinnedPost, ...retData.updatedPosts];
|
||||
}
|
||||
|
||||
return retData
|
||||
|
||||
|
||||
return retData;
|
||||
} catch (err) {
|
||||
setTabMeta({
|
||||
...tabMeta,
|
||||
isLoading:false,
|
||||
isRefreshing:false,
|
||||
})
|
||||
isLoading: false,
|
||||
isRefreshing: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
export const fetchPromotedEntries = async (username:string) => {
|
||||
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)
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Failed to get promoted posts, ', err);
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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<number, any>,
|
||||
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<number, any>;
|
||||
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,
|
||||
}
|
||||
startPermlink: string;
|
||||
startAuthor: string;
|
||||
isLoading: boolean;
|
||||
isRefreshing: boolean;
|
||||
isNoPost: boolean;
|
||||
}
|
||||
|
||||
export interface LoadPostsOptions {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
||||
@ -131,7 +126,6 @@ const TabEmptyView = ({
|
||||
setRecommendedUsers(recommendeds);
|
||||
}, [followingUsers]);
|
||||
|
||||
|
||||
//fetching
|
||||
const _getRecommendedUsers = () => dispatch(fetchLeaderboard());
|
||||
const _getRecommendedCommunities = () => dispatch(fetchCommunities('', 10));
|
||||
@ -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 (
|
||||
<NoPost
|
||||
imageStyle={styles.noImage}
|
||||
@ -245,7 +239,6 @@ const TabEmptyView = ({
|
||||
|
||||
if (isNoPost) {
|
||||
if (filterKey === 'friends') {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text style={[globalStyles.subTitle, styles.noPostTitle]}>
|
||||
@ -328,9 +321,7 @@ const TabEmptyView = ({
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<EmptyScreen style={styles.emptyAnimationContainer} />
|
||||
)
|
||||
return <EmptyScreen style={styles.emptyAnimationContainer} />;
|
||||
}
|
||||
}
|
||||
|
||||
@ -342,4 +333,3 @@ const TabEmptyView = ({
|
||||
};
|
||||
|
||||
export default withNavigation(TabEmptyView);
|
||||
|
||||
|
@ -1,26 +1,26 @@
|
||||
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 = ({
|
||||
@ -32,10 +32,8 @@ export const StackedTabBar = ({
|
||||
initialFirstStackIndex,
|
||||
onFilterSelect,
|
||||
toggleHideImagesFlag,
|
||||
pageType
|
||||
|
||||
}:StackedTabBarProps) => {
|
||||
|
||||
pageType,
|
||||
}: StackedTabBarProps) => {
|
||||
const dispatch = useDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
@ -49,16 +47,15 @@ export const StackedTabBar = ({
|
||||
|
||||
const enableCustomTabs = pageType !== undefined;
|
||||
|
||||
|
||||
const _onCustomisePress = () => {
|
||||
if(customiseModalRef.current){
|
||||
if (customiseModalRef.current) {
|
||||
customiseModalRef.current.show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _onToggleImagesPress = () => {
|
||||
dispatch(setHidePostsThumbnails(!isHideImages))
|
||||
}
|
||||
dispatch(setHidePostsThumbnails(!isHideImages));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -66,54 +63,43 @@ export const StackedTabBar = ({
|
||||
options={firstStack.map((item, index) => {
|
||||
return tabs[index]
|
||||
? tabs[index]
|
||||
: intl.formatMessage({ id: item.label.toLowerCase() }).toUpperCase()
|
||||
})
|
||||
}
|
||||
|
||||
: 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 && (
|
||||
{selectedFilterIndex == 0 && shouldStack && (
|
||||
<FilterBar
|
||||
options={secondStack.map((item) =>
|
||||
intl.formatMessage({ id: item.label.toLowerCase() }).toUpperCase(),
|
||||
)}
|
||||
selectedOptionIndex={selectedSecondStackIndex}
|
||||
onDropdownSelect={(index)=>{
|
||||
setSelectedSecondStackIndex(index)
|
||||
onDropdownSelect={(index) => {
|
||||
setSelectedSecondStackIndex(index);
|
||||
onFilterSelect(secondStack[index].filterKey);
|
||||
goToPage(firstStack.length + index);
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
{enableCustomTabs && (
|
||||
<CustomiseFiltersModal
|
||||
pageType={pageType}
|
||||
ref={customiseModalRef}
|
||||
/>
|
||||
)}
|
||||
|
||||
{enableCustomTabs && <CustomiseFiltersModal pageType={pageType} ref={customiseModalRef} />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -1,23 +1,23 @@
|
||||
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;
|
||||
@ -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<any[]>([]);
|
||||
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<PostsListRef>()
|
||||
let postsListRef = useRef<PostsListRef>();
|
||||
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,187 +79,181 @@ 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,
|
||||
isLatestPostsCheck: false,
|
||||
_feedUsername,
|
||||
_posts:initialPosts,
|
||||
_tabMeta:DEFAULT_TAB_META
|
||||
_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
|
||||
shouldReset: false,
|
||||
isLatestPostsCheck,
|
||||
});
|
||||
},
|
||||
timeLeft
|
||||
);
|
||||
setPostFetchTimer(_postFetchTimer)
|
||||
}, 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]);
|
||||
@ -274,84 +262,83 @@ const TabContent = ({
|
||||
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])
|
||||
_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 <TabEmptyView filterKey={filterKey} isNoPost={tabMeta.isNoPost}/>
|
||||
}
|
||||
return <TabEmptyView filterKey={filterKey} isNoPost={tabMeta.isNoPost} />;
|
||||
};
|
||||
|
||||
|
||||
const scrollPopupDebouce = debounce((value)=>{
|
||||
const scrollPopupDebouce = debounce(
|
||||
(value) => {
|
||||
setEnableScrollTop(value);
|
||||
}, 500, {leading:true})
|
||||
},
|
||||
500,
|
||||
{ leading: true },
|
||||
);
|
||||
|
||||
const _onScroll = (event:NativeSyntheticEvent<NativeScrollEvent>)=>{
|
||||
const _onScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {
|
||||
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
|
||||
console.log('Not LoggedIn');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
<>
|
||||
<PostsList
|
||||
ref={postsListRef}
|
||||
data={posts}
|
||||
isFeedScreen={isFeedScreen}
|
||||
promotedPosts={promotedPosts}
|
||||
onLoadPosts={(shouldReset)=>{
|
||||
_loadPosts({shouldReset})
|
||||
if(shouldReset){
|
||||
_getPromotedPosts()
|
||||
onLoadPosts={(shouldReset) => {
|
||||
_loadPosts({ shouldReset });
|
||||
if (shouldReset) {
|
||||
_getPromotedPosts();
|
||||
}
|
||||
}}
|
||||
onScroll={_onScroll}
|
||||
@ -363,11 +350,11 @@ const TabContent = ({
|
||||
showQuickReplyModal={_showQuickReplyModal}
|
||||
/>
|
||||
<ScrollTopPopup
|
||||
popupAvatars={latestPosts.map(post=>post.avatar || '')}
|
||||
popupAvatars={latestPosts.map((post) => post.avatar || '')}
|
||||
enableScrollTop={enableScrollTop}
|
||||
onPress={_onPostsPopupPress}
|
||||
onClose={()=>{
|
||||
setLatestPosts([])
|
||||
onClose={() => {
|
||||
setLatestPosts([]);
|
||||
setEnableScrollTop(false);
|
||||
}}
|
||||
/>
|
||||
@ -376,4 +363,3 @@ const TabContent = ({
|
||||
};
|
||||
|
||||
export default TabContent;
|
||||
|
||||
|
@ -7,13 +7,13 @@ import { useAppSelector } from '../../../hooks';
|
||||
import styles from './textInputStyles';
|
||||
|
||||
interface Props extends TextInputProps {
|
||||
innerRef: Ref<TextInput>,
|
||||
height: number,
|
||||
style: TextStyle
|
||||
innerRef: Ref<TextInput>;
|
||||
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 (
|
||||
<TextInput
|
||||
ref={innerRef}
|
||||
@ -22,7 +22,7 @@ const TextInputView = ({ innerRef, height, style, ...props }: Props) => {
|
||||
{...props}
|
||||
style={[styles.input, { minHeight: height }, style]}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default TextInputView;
|
||||
|
@ -54,7 +54,7 @@ export default EStyleSheet.create({
|
||||
textAlign: 'right',
|
||||
},
|
||||
centerDescription: {
|
||||
marginTop:8,
|
||||
marginTop: 8,
|
||||
fontSize: 12,
|
||||
color: '$primaryBlack',
|
||||
fontWeight: '600',
|
||||
|
@ -57,7 +57,7 @@ const UploadsGalleryContent = ({
|
||||
|
||||
const animatedHeightRef = useRef(new Animated.Value(COMPACT_HEIGHT));
|
||||
|
||||
const isDeleting = deleteMediaMutation.isLoading
|
||||
const isDeleting = deleteMediaMutation.isLoading;
|
||||
|
||||
useEffect(() => {
|
||||
if (isExpandedMode) {
|
||||
@ -65,13 +65,12 @@ const UploadsGalleryContent = ({
|
||||
}
|
||||
}, [isExpandedMode]);
|
||||
|
||||
|
||||
const _deleteMedia = async () => {
|
||||
deleteMediaMutation.mutate(deleteIds, {
|
||||
onSettled: () => {
|
||||
setIsDeleteMode(false);
|
||||
setDeleteIds([]);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
});
|
||||
|
@ -198,12 +198,14 @@ export const UploadsGalleryModal = forwardRef(
|
||||
setIsAddingToUploads(true);
|
||||
}
|
||||
|
||||
await mediaUploadMutation.mutateAsync({
|
||||
await mediaUploadMutation.mutateAsync(
|
||||
{
|
||||
media,
|
||||
addToUploads: !shouldInsert
|
||||
}, {
|
||||
addToUploads: !shouldInsert,
|
||||
},
|
||||
{
|
||||
onSuccess: (data) => {
|
||||
console.log('upload successfully', data, media, shouldInsert)
|
||||
console.log('upload successfully', data, media, shouldInsert);
|
||||
if (data && data.url && shouldInsert) {
|
||||
_handleMediaInsertion({
|
||||
filename: media.filename,
|
||||
@ -219,9 +221,11 @@ export const UploadsGalleryModal = forwardRef(
|
||||
}
|
||||
setIsAddingToUploads(false);
|
||||
},
|
||||
onError: (err) => { throw err },
|
||||
})
|
||||
|
||||
onError: (err) => {
|
||||
throw err;
|
||||
},
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
console.log('error while uploading image : ', error);
|
||||
|
||||
@ -300,8 +304,6 @@ export const UploadsGalleryModal = forwardRef(
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//fetch images from server
|
||||
const _getMediaUploads = async () => {
|
||||
try {
|
||||
|
@ -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);
|
||||
|
@ -8,5 +8,4 @@ const coingeckoApi = axios.create({
|
||||
baseURL: `${BASE_URL}/${PATH_API}/${API_VERSION}`,
|
||||
});
|
||||
|
||||
|
||||
export default coingeckoApi;
|
@ -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;
|
||||
});
|
||||
|
||||
|
@ -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
|
||||
export default DEFAULT_COINS;
|
||||
|
@ -1,6 +1,5 @@
|
||||
export default [
|
||||
{key:'settings.theme.system', value: null},
|
||||
{key:'settings.theme.light', value: false},
|
||||
{key:'settings.theme.dark', value: true}
|
||||
];
|
||||
|
||||
{ key: 'settings.theme.system', value: null },
|
||||
{ key: 'settings.theme.light', value: false },
|
||||
{ key: 'settings.theme.dark', value: true },
|
||||
];
|
||||
|
@ -4,5 +4,5 @@ const DELETE_ACCOUNT = 'delete_account';
|
||||
|
||||
export default {
|
||||
SHOW_HIDE_IMGS,
|
||||
DELETE_ACCOUNT
|
||||
DELETE_ACCOUNT,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 this._consumeAvailablePurchases()
|
||||
await this._consumeAvailablePurchases();
|
||||
this._getItems();
|
||||
this._purchaseUpdatedListener();
|
||||
await this._handleQrPurchase();
|
||||
@ -70,17 +67,15 @@ class InAppPurchaseContainer extends Component {
|
||||
intl.formatMessage({
|
||||
id: 'alert.connection_issues',
|
||||
}),
|
||||
err.message
|
||||
err.message,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//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
|
||||
@ -88,12 +83,11 @@ class InAppPurchaseContainer extends Component {
|
||||
//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
|
||||
|
||||
@ -157,7 +151,7 @@ class InAppPurchaseContainer extends Component {
|
||||
intl.formatMessage({
|
||||
id: 'alert.warning',
|
||||
}),
|
||||
error.message
|
||||
error.message,
|
||||
);
|
||||
}
|
||||
this.setState({ isProcessing: false });
|
||||
@ -186,7 +180,7 @@ class InAppPurchaseContainer extends Component {
|
||||
intl.formatMessage({
|
||||
id: 'alert.connection_issues',
|
||||
}),
|
||||
error.message
|
||||
error.message,
|
||||
);
|
||||
}
|
||||
|
||||
@ -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}`
|
||||
});
|
||||
price: `${product.currency} ${product.price}`,
|
||||
},
|
||||
);
|
||||
|
||||
let title = intl.formatMessage({
|
||||
id: 'boost.confirm_purchase'
|
||||
}, {
|
||||
let title = intl.formatMessage(
|
||||
{
|
||||
id: 'boost.confirm_purchase',
|
||||
},
|
||||
{
|
||||
username,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
dispatch(
|
||||
showActionModal({
|
||||
@ -251,12 +251,11 @@ class InAppPurchaseContainer extends Component {
|
||||
onPress: async () => await this._buyItem(productId),
|
||||
},
|
||||
],
|
||||
headerContent: <UserAvatar username={username} size='xl' />,
|
||||
headerContent: <UserAvatar username={username} size="xl" />,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children, isNoSpin, navigation } = this.props;
|
||||
@ -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,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -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 (
|
||||
<NavigationContainer ref={ref=>setTopLevelNavigator(ref)}>
|
||||
<NavigationContainer ref={(ref) => setTopLevelNavigator(ref)}>
|
||||
<StackNavigator initRoute={_initRoute} />
|
||||
</NavigationContainer>
|
||||
)
|
||||
}
|
||||
|
||||
);
|
||||
};
|
||||
|
@ -1,38 +1,29 @@
|
||||
|
||||
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 (
|
||||
<Tab.Navigator
|
||||
tabBar={(props) => <BottomTabBar {...props} /> }
|
||||
|
||||
backBehavior='initialRoute'
|
||||
tabBar={(props) => <BottomTabBar {...props} />}
|
||||
backBehavior="initialRoute"
|
||||
screenOptions={{
|
||||
headerShown:false,
|
||||
headerShown: false,
|
||||
tabBarShowLabel: false,
|
||||
tabBarActiveTintColor: '#357ce6',
|
||||
tabBarInactiveTintColor: '#c1c5c7',}}
|
||||
tabBarInactiveTintColor: '#c1c5c7',
|
||||
}}
|
||||
>
|
||||
<Tab.Screen
|
||||
name={ROUTES.TABBAR.FEED}
|
||||
component={Feed}
|
||||
initialParams={{
|
||||
iconName: 'view-day' //read in bottomTabBarView
|
||||
iconName: 'view-day', //read in bottomTabBarView
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -40,7 +31,7 @@ export const BottomTabNavigator = () => {
|
||||
name={ROUTES.TABBAR.NOTIFICATION}
|
||||
component={Notification}
|
||||
initialParams={{
|
||||
iconName: 'notifications' //read in bottomTabBarView
|
||||
iconName: 'notifications', //read in bottomTabBarView
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -48,7 +39,7 @@ export const BottomTabNavigator = () => {
|
||||
name={ROUTES.TABBAR.POST_BUTTON}
|
||||
component={EmptyScreen}
|
||||
initialParams={{
|
||||
iconName: 'pencil' //read in bottomTabBarView
|
||||
iconName: 'pencil', //read in bottomTabBarView
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -56,7 +47,7 @@ export const BottomTabNavigator = () => {
|
||||
name={ROUTES.TABBAR.WALLET}
|
||||
component={Wallet}
|
||||
initialParams={{
|
||||
iconName: 'account-balance-wallet' //read in bottomTabBarView
|
||||
iconName: 'account-balance-wallet', //read in bottomTabBarView
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -64,12 +55,11 @@ export const BottomTabNavigator = () => {
|
||||
name={ROUTES.TABBAR.PROFILE}
|
||||
component={Profile}
|
||||
initialParams={{
|
||||
iconName: 'person' //read in bottomTabBarView
|
||||
iconName: 'person', //read in bottomTabBarView
|
||||
}}
|
||||
/>
|
||||
</Tab.Navigator>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const EmptyScreen = () => null
|
||||
const EmptyScreen = () => null;
|
||||
|
@ -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 (
|
||||
<Drawer.Navigator screenOptions={{headerShown:false}} drawerContent={(props) => <SideMenu {...props}/>} >
|
||||
<Drawer.Navigator
|
||||
screenOptions={{ headerShown: false }}
|
||||
drawerContent={(props) => <SideMenu {...props} />}
|
||||
>
|
||||
<Drawer.Screen name={ROUTES.SCREENS.FEED} component={BottomTabNavigator} />
|
||||
</Drawer.Navigator>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -1,9 +1,9 @@
|
||||
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,
|
||||
@ -36,13 +36,12 @@ import {
|
||||
} from '../screens';
|
||||
import { DrawerNavigator } from './drawerNavigator';
|
||||
|
||||
|
||||
const RootStack = createNativeStackNavigator();
|
||||
const MainStack = createNativeStackNavigator();
|
||||
|
||||
const MainStackNavigator = () => {
|
||||
return (
|
||||
<MainStack.Navigator screenOptions={{ headerShown: false, animation: 'slide_from_right' }} >
|
||||
<MainStack.Navigator screenOptions={{ headerShown: false, animation: 'slide_from_right' }}>
|
||||
<MainStack.Screen name={ROUTES.DRAWER.MAIN} component={DrawerNavigator} />
|
||||
<MainStack.Screen name={ROUTES.SCREENS.PROFILE} component={Profile} />
|
||||
<MainStack.Screen name={ROUTES.SCREENS.PROFILE_EDIT} component={ProfileEdit} />
|
||||
@ -70,25 +69,27 @@ const MainStackNavigator = () => {
|
||||
<MainStack.Screen name={ROUTES.SCREENS.EDITOR} component={Editor} />
|
||||
</MainStack.Group>
|
||||
</MainStack.Navigator>
|
||||
)
|
||||
}
|
||||
|
||||
export const StackNavigator = ({initRoute}) => {
|
||||
);
|
||||
};
|
||||
|
||||
export const StackNavigator = ({ initRoute }) => {
|
||||
return (
|
||||
<RootStack.Navigator
|
||||
|
||||
initialRouteName={initRoute}
|
||||
screenOptions={{ headerShown: false, animation:'slide_from_bottom' }}>
|
||||
screenOptions={{ headerShown: false, animation: 'slide_from_bottom' }}
|
||||
|
||||
<RootStack.Screen name={ROUTES.STACK.MAIN} component={MainStackNavigator} />
|
||||
|
||||
<RootStack.Screen name={ROUTES.SCREENS.REGISTER} component={Register} />
|
||||
<RootStack.Screen name={ROUTES.SCREENS.LOGIN} component={Login} />
|
||||
<RootStack.Screen name={ROUTES.SCREENS.WELCOME} component={WelcomeScreen}/>
|
||||
<RootStack.Screen name={ROUTES.SCREENS.PINCODE} options={{gestureEnabled:false}} component={PinCode}/>
|
||||
<RootStack.Screen name={ROUTES.SCREENS.WELCOME} component={WelcomeScreen} />
|
||||
<RootStack.Screen
|
||||
name={ROUTES.SCREENS.PINCODE}
|
||||
options={{ gestureEnabled: false }}
|
||||
component={PinCode}
|
||||
/>
|
||||
</RootStack.Navigator>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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<MarketData> => {
|
||||
try{
|
||||
coingeckoId: string,
|
||||
vs_currency: string,
|
||||
days: number,
|
||||
interval: 'daily' | 'hourly' = 'daily',
|
||||
): Promise<MarketData> => {
|
||||
try {
|
||||
const params = {
|
||||
vs_currency,
|
||||
days,
|
||||
interval
|
||||
}
|
||||
interval,
|
||||
};
|
||||
|
||||
const res = await coingeckoApi.get(`/${PATH_COINS}/${coingeckoId}/${PATH_MARKET_CHART}`, {
|
||||
params
|
||||
params,
|
||||
});
|
||||
const rawData = res.data;
|
||||
if(!rawData){
|
||||
throw new Error("Tag name not available")
|
||||
if (!rawData) {
|
||||
throw new Error('Tag name not available');
|
||||
}
|
||||
|
||||
const data = convertMarketData(rawData);
|
||||
|
||||
return data;
|
||||
|
||||
}catch(error){
|
||||
} catch (error) {
|
||||
bugsnagInstance.notify(error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -1,23 +1,23 @@
|
||||
import { ChartItem, MarketData } from "./models"
|
||||
import { ChartItem, MarketData } from './models';
|
||||
|
||||
export const convertChartItem = (rawData:any) => {
|
||||
if(!rawData){
|
||||
export const convertChartItem = (rawData: any) => {
|
||||
if (!rawData) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
xValue:rawData[0],
|
||||
yValue:rawData[1]
|
||||
xValue: rawData[0],
|
||||
yValue: rawData[1],
|
||||
} as ChartItem;
|
||||
}
|
||||
};
|
||||
|
||||
export const convertMarketData = (rawData:any) => {
|
||||
if(!rawData){
|
||||
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) : []
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
@ -1,10 +1,10 @@
|
||||
export interface ChartItem {
|
||||
xValue:number,
|
||||
yValue:number
|
||||
xValue: number;
|
||||
yValue: number;
|
||||
}
|
||||
|
||||
export interface MarketData {
|
||||
prices:Array<ChartItem>;
|
||||
marketCaps:Array<ChartItem>;
|
||||
totalVolumes:Array<ChartItem>;
|
||||
prices: Array<ChartItem>;
|
||||
marketCaps: Array<ChartItem>;
|
||||
totalVolumes: Array<ChartItem>;
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -4,7 +4,6 @@ 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
|
||||
@ -15,7 +14,6 @@ import { EcencyUser, UserPoint } from './ecency.types';
|
||||
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<EcencyUser> => {
|
||||
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<EcencyUser> => {
|
||||
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<UserPoint[]> =>
|
||||
new Promise((resolve) => {
|
||||
@ -60,18 +57,16 @@ export const getPointsHistory = (username: string): Promise<UserPoint[]> =>
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
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) => {
|
||||
|
@ -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,
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
export interface Vote {
|
||||
percent: number;
|
||||
reputation: number;
|
||||
@ -56,21 +55,20 @@ export interface MarketStatistics {
|
||||
}
|
||||
|
||||
export interface OpenOrderItem {
|
||||
id: number,
|
||||
created: string,
|
||||
expiration: string,
|
||||
seller: string,
|
||||
orderid: number,
|
||||
for_sale: number,
|
||||
id: number;
|
||||
created: string;
|
||||
expiration: string;
|
||||
seller: string;
|
||||
orderid: number;
|
||||
for_sale: number;
|
||||
sell_price: {
|
||||
base: string,
|
||||
quote: string
|
||||
},
|
||||
real_price: string,
|
||||
rewarded: boolean
|
||||
base: string;
|
||||
quote: string;
|
||||
};
|
||||
real_price: string;
|
||||
rewarded: boolean;
|
||||
}
|
||||
|
||||
|
||||
export interface OrdersDataItem {
|
||||
created: string;
|
||||
hbd: number;
|
||||
@ -78,7 +76,7 @@ export interface OrdersDataItem {
|
||||
order_price: {
|
||||
base: string;
|
||||
quote: string;
|
||||
}
|
||||
};
|
||||
real_price: string;
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,6 @@ interface MediaUploadVars {
|
||||
addToUploads: boolean;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** GET QUERIES **/
|
||||
|
||||
export const useMediaQuery = () => {
|
||||
@ -54,12 +52,8 @@ export const useSnippetsQuery = () => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** ADD UPDATE MUTATIONS **/
|
||||
|
||||
|
||||
export const useAddToUploadsMutation = () => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
@ -77,11 +71,9 @@ export const useAddToUploadsMutation = () => {
|
||||
} else {
|
||||
dispatch(toastNotification(intl.formatMessage({ id: 'alert.fail' })));
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export const useMediaUploadMutation = () => {
|
||||
const intl = useIntl();
|
||||
@ -89,8 +81,8 @@ export const useMediaUploadMutation = () => {
|
||||
|
||||
const addToUploadsMutation = useAddToUploadsMutation();
|
||||
|
||||
const currentAccount = useAppSelector(state => state.account.currentAccount);
|
||||
const pinCode = useAppSelector(state => state.application.pin);
|
||||
const currentAccount = useAppSelector((state) => state.account.currentAccount);
|
||||
const pinCode = useAppSelector((state) => state.application.pin);
|
||||
|
||||
return useMutation<Image, undefined, MediaUploadVars>(
|
||||
async ({ media }) => {
|
||||
@ -111,7 +103,7 @@ export const useMediaUploadMutation = () => {
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export const useSnippetsMutation = () => {
|
||||
const intl = useIntl();
|
||||
@ -164,26 +156,26 @@ export const useSnippetsMutation = () => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** DELETE MUTATIONS **/
|
||||
|
||||
export const useMediaDeleteMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
return useMutation<string[], undefined, string[]>(async (deleteIds) => {
|
||||
return useMutation<string[], undefined, string[]>(
|
||||
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)))
|
||||
const _newData = data.filter((item) => !deleteIds.includes(item._id));
|
||||
queryClient.setQueryData([QUERIES.MEDIA.GET], _newData);
|
||||
}
|
||||
},
|
||||
@ -191,10 +183,10 @@ export const useMediaDeleteMutation = () => {
|
||||
dispatch(toastNotification(intl.formatMessage({ id: 'uploads_modal.delete_failed' })));
|
||||
queryClient.invalidateQueries([QUERIES.MEDIA.GET]);
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export const useSnippetDeleteMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const dispatch = useAppDispatch();
|
||||
|
@ -26,4 +26,4 @@ export const initQueryClient = () => {
|
||||
export * from './notificationQueries';
|
||||
export * from './draftQueries';
|
||||
export * from './editorQueries';
|
||||
export * from './pointQueries'
|
||||
export * from './pointQueries';
|
||||
|
@ -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;
|
||||
blockNum?: string | number;
|
||||
transactionId?: string;
|
||||
cacheId?: string
|
||||
cacheId?: string;
|
||||
}
|
||||
|
||||
|
||||
export const useUserActivityMutation = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const currentAccount = useAppSelector(state => state.account.currentAccount);
|
||||
const pointActivitiesCache:Map<string, PointActivity> = useAppSelector(state => state.cache.pointActivities);
|
||||
|
||||
const currentAccount = useAppSelector((state) => state.account.currentAccount);
|
||||
const pointActivitiesCache: Map<string, PointActivity> = useAppSelector(
|
||||
(state) => state.cache.pointActivities,
|
||||
);
|
||||
|
||||
const _mutationFn = async ({ pointsTy, blockNum, transactionId }: UserActivityMutationVars) => {
|
||||
|
||||
await userActivity(pointsTy, transactionId, blockNum)
|
||||
await userActivity(pointsTy, transactionId, blockNum);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
const mutation = useMutation<boolean, Error, UserActivityMutationVars>(_mutationFn, {
|
||||
retry: 2,
|
||||
onSuccess: (data, vars) => {
|
||||
console.log("successfully logged activity", 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))
|
||||
console.log('must remove from redux');
|
||||
dispatch(deletePointActivityCache(vars.cacheId));
|
||||
}
|
||||
},
|
||||
onError: (error, vars) => {
|
||||
console.log("failed to log activity", 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")
|
||||
console.log('must add to from redux');
|
||||
const cacheId = generateRndStr();
|
||||
const { username } = currentAccount;
|
||||
dispatch(updatePointActivityCache(cacheId, { ...vars, username }))
|
||||
dispatch(updatePointActivityCache(cacheId, { ...vars, username }));
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
const lazyMutatePendingActivities = () => {
|
||||
setTimeout(()=>{
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
return {
|
||||
...mutation,
|
||||
lazyMutatePendingActivities,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -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<string>;
|
||||
}
|
||||
|
||||
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.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({
|
||||
comment.body = renderPostBody(
|
||||
{
|
||||
author: comment.author,
|
||||
permlink: comment.permlink,
|
||||
last_update: comment.updated,
|
||||
body: comment.markdownBody,
|
||||
}, true, Platform.OS === 'android');
|
||||
},
|
||||
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,
|
||||
});
|
||||
|
@ -1,6 +1,13 @@
|
||||
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';
|
||||
|
||||
@ -9,55 +16,56 @@ export const setSelectedCoins = (coins: CoinBase[]) => ({
|
||||
type: SET_SELECTED_COINS,
|
||||
});
|
||||
|
||||
|
||||
|
||||
export const setCoinsData = (data: { [key: string]: CoinData }, vsCurrency: string, username: string) => ({
|
||||
export const setCoinsData = (
|
||||
data: { [key: string]: CoinData },
|
||||
vsCurrency: string,
|
||||
username: string,
|
||||
) => ({
|
||||
payload: {
|
||||
data,
|
||||
vsCurrency,
|
||||
username,
|
||||
},
|
||||
type: SET_COINS_DATA
|
||||
})
|
||||
type: SET_COINS_DATA,
|
||||
});
|
||||
|
||||
export const setPriceHistory = (coinId: string, vsCurrency: string, data: number[]) => ({
|
||||
payload: {
|
||||
id: coinId,
|
||||
vsCurrency,
|
||||
data
|
||||
data,
|
||||
},
|
||||
type: SET_PRICE_HISTORY
|
||||
})
|
||||
type: SET_PRICE_HISTORY,
|
||||
});
|
||||
|
||||
export const setCoinActivities = (coinId: string, data: CoinActivitiesCollection) => ({
|
||||
payload: {
|
||||
id: coinId,
|
||||
data,
|
||||
},
|
||||
type: SET_COIN_ACTIVITIES
|
||||
})
|
||||
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)
|
||||
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) => {
|
||||
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;
|
||||
@ -71,12 +79,8 @@ export const fetchAndSetCoinsData = (refresh: boolean = false) => async (dispatc
|
||||
currencyRate: currency.currencyRate,
|
||||
globalProps,
|
||||
quotes,
|
||||
refresh
|
||||
})
|
||||
refresh,
|
||||
});
|
||||
|
||||
return dispatch(setCoinsData(
|
||||
coinsData,
|
||||
currency.currency,
|
||||
currentAccount.username
|
||||
))
|
||||
}
|
||||
return dispatch(setCoinsData(coinsData, currency.currency, currentAccount.username));
|
||||
};
|
||||
|
@ -1,6 +1,5 @@
|
||||
export const statusMessage = {
|
||||
PENDING : 'PENDING',
|
||||
SUCCESS : 'SUCCESS',
|
||||
FAIL : 'FAIL',
|
||||
PENDING: 'PENDING',
|
||||
SUCCESS: 'SUCCESS',
|
||||
FAIL: 'FAIL',
|
||||
};
|
||||
|
@ -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) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { PointActivity } from "../../providers/ecency/ecency.types";
|
||||
import { PointActivity } from '../../providers/ecency/ecency.types';
|
||||
import {
|
||||
PURGE_EXPIRED_CACHE,
|
||||
UPDATE_VOTE_CACHE,
|
||||
@ -10,8 +10,8 @@ import {
|
||||
DELETE_SUBSCRIBED_COMMUNITY_CACHE,
|
||||
CLEAR_SUBSCRIBED_COMMUNITIES_CACHE,
|
||||
UPDATE_POINT_ACTIVITY_CACHE,
|
||||
DELETE_POINT_ACTIVITY_CACHE_ENTRY
|
||||
} from "../constants/constants";
|
||||
DELETE_POINT_ACTIVITY_CACHE_ENTRY,
|
||||
} from '../constants/constants';
|
||||
|
||||
export enum CommentCacheStatus {
|
||||
PENDING = 'PENDING',
|
||||
@ -28,52 +28,51 @@ export interface Vote {
|
||||
}
|
||||
|
||||
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,
|
||||
author: string;
|
||||
body: string;
|
||||
title?: string;
|
||||
tags?: string;
|
||||
meta?: any;
|
||||
created?: number;
|
||||
updated?: number;
|
||||
expiresAt?: number;
|
||||
}
|
||||
|
||||
export interface SubscribedCommunity {
|
||||
data: Array<any>,
|
||||
data: Array<any>;
|
||||
expiresAt?: number;
|
||||
}
|
||||
|
||||
|
||||
interface State {
|
||||
votes: Map<string, Vote>
|
||||
comments: Map<string, Comment> //TODO: handle comment array per post, if parent is same
|
||||
drafts: Map<string, Draft>
|
||||
subscribedCommunities: Map<string, SubscribedCommunity>
|
||||
pointActivities: Map<string, PointActivity>
|
||||
votes: Map<string, Vote>;
|
||||
comments: Map<string, Comment>; //TODO: handle comment array per post, if parent is same
|
||||
drafts: Map<string, Draft>;
|
||||
subscribedCommunities: Map<string, SubscribedCommunity>;
|
||||
pointActivities: Map<string, PointActivity>;
|
||||
lastUpdate: {
|
||||
postPath: string,
|
||||
updatedAt: number,
|
||||
type: 'vote' | 'comment' | 'draft',
|
||||
}
|
||||
postPath: string;
|
||||
updatedAt: number;
|
||||
type: 'vote' | 'comment' | 'draft';
|
||||
};
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
@ -99,7 +98,7 @@ export default function (state = initialState, action) {
|
||||
postPath: payload.postPath,
|
||||
updatedAt: new Date().getTime(),
|
||||
type: 'vote',
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
case UPDATE_COMMENT_CACHE:
|
||||
@ -112,15 +111,15 @@ export default function (state = initialState, action) {
|
||||
lastUpdate: {
|
||||
postPath: payload.commentPath,
|
||||
updatedAt: new Date().getTime(),
|
||||
type: 'comment'
|
||||
}
|
||||
type: 'comment',
|
||||
},
|
||||
};
|
||||
|
||||
case DELETE_COMMENT_CACHE_ENTRY:
|
||||
if (state.comments && state.comments.has(payload)) {
|
||||
state.comments.delete(payload);
|
||||
}
|
||||
return { ...state }
|
||||
return { ...state };
|
||||
|
||||
case UPDATE_DRAFT_CACHE:
|
||||
if (!state.drafts) {
|
||||
@ -133,7 +132,7 @@ export default function (state = initialState, action) {
|
||||
|
||||
payloadDraft.created = curDraft ? curDraft.created : curTime;
|
||||
payloadDraft.updated = curTime;
|
||||
payloadDraft.expiresAt = curTime + 604800000 // 7 days ms
|
||||
payloadDraft.expiresAt = curTime + 604800000; // 7 days ms
|
||||
|
||||
state.drafts.set(payload.id, payloadDraft);
|
||||
return {
|
||||
@ -149,7 +148,7 @@ export default function (state = initialState, action) {
|
||||
if (state.drafts && state.drafts.has(payload)) {
|
||||
state.drafts.delete(payload);
|
||||
}
|
||||
return { ...state }
|
||||
return { ...state };
|
||||
|
||||
case UPDATE_SUBSCRIBED_COMMUNITY_CACHE:
|
||||
if (!state.subscribedCommunities) {
|
||||
@ -159,19 +158,19 @@ export default function (state = initialState, action) {
|
||||
subscribedCommunities.set(payload.path, payload.subscribedCommunity);
|
||||
return {
|
||||
...state, //spread operator in requried here, otherwise persist do not register change
|
||||
subscribedCommunities: subscribedCommunities
|
||||
subscribedCommunities: subscribedCommunities,
|
||||
};
|
||||
|
||||
case DELETE_SUBSCRIBED_COMMUNITY_CACHE:
|
||||
if (state.subscribedCommunities && state.subscribedCommunities.has(payload)) {
|
||||
state.subscribedCommunities.delete(payload);
|
||||
}
|
||||
return { ...state }
|
||||
return { ...state };
|
||||
|
||||
case CLEAR_SUBSCRIBED_COMMUNITIES_CACHE:
|
||||
state.subscribedCommunities = new Map<string, SubscribedCommunity>();
|
||||
|
||||
return { ...state }
|
||||
return { ...state };
|
||||
|
||||
case UPDATE_POINT_ACTIVITY_CACHE:
|
||||
if (!state.pointActivities) {
|
||||
@ -186,7 +185,7 @@ export default function (state = initialState, action) {
|
||||
if (state.pointActivities && state.pointActivities.has(payload)) {
|
||||
state.pointActivities.delete(payload);
|
||||
}
|
||||
return { ...state }
|
||||
return { ...state };
|
||||
|
||||
case PURGE_EXPIRED_CACHE:
|
||||
const currentTime = new Date().getTime();
|
||||
@ -196,7 +195,7 @@ export default function (state = initialState, action) {
|
||||
if (entry[1].expiresAt < currentTime) {
|
||||
state.votes.delete(entry[0]);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (state.comments && state.comments.size) {
|
||||
@ -204,7 +203,7 @@ export default function (state = initialState, action) {
|
||||
if (entry[1].expiresAt < currentTime) {
|
||||
state.comments.delete(entry[0]);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (state.drafts && state.drafts.size) {
|
||||
@ -212,9 +211,7 @@ export default function (state = initialState, action) {
|
||||
if (entry[1].expiresAt < currentTime || !entry[1].body) {
|
||||
state.drafts.delete(entry[0]);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
if (state.subscribedCommunities && state.subscribedCommunities.size) {
|
||||
@ -222,14 +219,13 @@ export default function (state = initialState, action) {
|
||||
if (entry[1].expiresAt < currentTime) {
|
||||
state.subscribedCommunities.delete(entry[0]);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...state
|
||||
}
|
||||
...state,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:{}
|
||||
};
|
||||
const initialState: State = {
|
||||
beneficiariesMap: {},
|
||||
};
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
const {type, payload} = action;
|
||||
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
|
||||
...state, //spread operator in requried here, otherwise persist do not register change
|
||||
};
|
||||
case REMOVE_BENEFICIARIES:
|
||||
delete state.beneficiariesMap[payload.draftId]
|
||||
delete state.beneficiariesMap[payload.draftId];
|
||||
return {
|
||||
...state //spread operator in requried here, otherwise persist do not register change
|
||||
...state, //spread operator in requried here, otherwise persist do not register change
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,136 +1,140 @@
|
||||
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;
|
||||
trxIndex: number;
|
||||
iconType: string;
|
||||
textKey: string;
|
||||
created: string;
|
||||
expires: string;
|
||||
icon: string;
|
||||
value: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:{
|
||||
selectedCoins: CoinBase[];
|
||||
coinsData: {
|
||||
[key: string]: CoinData;
|
||||
},
|
||||
priceHistories:{
|
||||
};
|
||||
priceHistories: {
|
||||
[key: string]: PriceHistory;
|
||||
}
|
||||
coinsActivities:{
|
||||
[key: string]:CoinActivitiesCollection;
|
||||
},
|
||||
quotes:{
|
||||
};
|
||||
coinsActivities: {
|
||||
[key: string]: CoinActivitiesCollection;
|
||||
};
|
||||
quotes: {
|
||||
[key: string]: QuoteItem;
|
||||
}
|
||||
vsCurrency:string,
|
||||
username:string,
|
||||
updateTimestamp:number;
|
||||
};
|
||||
vsCurrency: string;
|
||||
username: string;
|
||||
updateTimestamp: number;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const initialState:State = {
|
||||
selectedCoins:DEFAULT_COINS,
|
||||
coinsData:{},
|
||||
priceHistories:{},
|
||||
coinsActivities:{},
|
||||
const initialState: State = {
|
||||
selectedCoins: DEFAULT_COINS,
|
||||
coinsData: {},
|
||||
priceHistories: {},
|
||||
coinsActivities: {},
|
||||
quotes: null,
|
||||
vsCurrency:'',
|
||||
username:'',
|
||||
updateTimestamp:0
|
||||
vsCurrency: '',
|
||||
username: '',
|
||||
updateTimestamp: 0,
|
||||
};
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
const {type, payload} = action;
|
||||
const { type, payload } = action;
|
||||
switch (type) {
|
||||
case RESET_WALLET_DATA:{
|
||||
case RESET_WALLET_DATA: {
|
||||
return {
|
||||
...initialState,
|
||||
selectedCoins:state.selectedCoins
|
||||
selectedCoins: state.selectedCoins,
|
||||
};
|
||||
}
|
||||
}
|
||||
case SET_SELECTED_COINS:{
|
||||
case SET_SELECTED_COINS: {
|
||||
return {
|
||||
...state,
|
||||
selectedCoin:payload
|
||||
selectedCoin: payload,
|
||||
};
|
||||
}
|
||||
}
|
||||
case SET_COINS_DATA:{
|
||||
case SET_COINS_DATA: {
|
||||
return {
|
||||
...state,
|
||||
coinsData:payload.data,
|
||||
vsCurrency:payload.vsCurrency,
|
||||
username:payload.username,
|
||||
updateTimestamp:new Date().getTime()
|
||||
coinsData: payload.data,
|
||||
vsCurrency: payload.vsCurrency,
|
||||
username: payload.username,
|
||||
updateTimestamp: new Date().getTime(),
|
||||
};
|
||||
}
|
||||
}
|
||||
case SET_PRICE_HISTORY:{
|
||||
case SET_PRICE_HISTORY: {
|
||||
state.priceHistories[payload.id] = {
|
||||
expiresAt:new Date().getTime() + ONE_HOUR_MS,
|
||||
vsCurrency:payload.vsCurrency,
|
||||
data:payload.data
|
||||
expiresAt: new Date().getTime() + ONE_HOUR_MS,
|
||||
vsCurrency: payload.vsCurrency,
|
||||
data: payload.data,
|
||||
};
|
||||
return {
|
||||
...state
|
||||
...state,
|
||||
};
|
||||
}
|
||||
}
|
||||
case SET_COIN_ACTIVITIES:{
|
||||
state.coinsActivities[payload.id] = payload.data
|
||||
return {
|
||||
...state
|
||||
}
|
||||
}
|
||||
case SET_COIN_QUOTES:{
|
||||
case SET_COIN_ACTIVITIES: {
|
||||
state.coinsActivities[payload.id] = payload.data;
|
||||
return {
|
||||
...state,
|
||||
quotes:payload,
|
||||
};
|
||||
}
|
||||
case SET_COIN_QUOTES: {
|
||||
return {
|
||||
...state,
|
||||
quotes: payload,
|
||||
};
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
|
@ -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'] },
|
||||
);
|
||||
|
@ -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 {
|
||||
<StatusBar barStyle={barStyle} backgroundColor={barColor} />
|
||||
)}
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
_renderAppNavigator() {
|
||||
const { isConnected } = this.props;
|
||||
return (
|
||||
@ -121,13 +116,10 @@ class ApplicationScreen extends Component {
|
||||
{!isConnected && <NoInternetConnection />}
|
||||
|
||||
<AppNavigator />
|
||||
|
||||
</Fragment>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
_renderAppModals() {
|
||||
const { toastNotification, foregroundNotificationData } = this.props;
|
||||
const { isShowToastNotification } = this.state;
|
||||
@ -148,11 +140,9 @@ class ApplicationScreen extends Component {
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
};
|
||||
|
@ -6,10 +6,10 @@ export default EStyleSheet.create({
|
||||
borderBottomWidth: EStyleSheet.hairlineWidth,
|
||||
borderColor: '$darkGrayBackground',
|
||||
marginBottom: 0, //without 0 margin, view will start overlapping UserRibbon
|
||||
paddingBottom: 32
|
||||
paddingBottom: 32,
|
||||
} as ViewStyle,
|
||||
|
||||
listContainer: {
|
||||
paddingTop: 16
|
||||
} as ViewStyle
|
||||
paddingTop: 16,
|
||||
} as ViewStyle,
|
||||
});
|
||||
|
@ -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<any> | ReactElement<any, string | JSXElementConstructor<any>>
|
||||
header: ComponentType<any> | ReactElement<any, string | JSXElementConstructor<any>>;
|
||||
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 <Transaction item={item} index={index} />
|
||||
}
|
||||
return <Transaction item={item} index={index} />;
|
||||
};
|
||||
|
||||
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 = (
|
||||
<RefreshControl
|
||||
@ -59,8 +56,7 @@ const ActivitiesList = ({
|
||||
titleColor="#fff"
|
||||
colors={['#fff']}
|
||||
/>
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
return (
|
||||
<SectionList
|
||||
@ -72,14 +68,16 @@ const ActivitiesList = ({
|
||||
renderSectionHeader={({ section: { title } }) => (
|
||||
<Text style={styles.textActivities}>{title}</Text>
|
||||
)}
|
||||
ListFooterComponent={loading && <ActivityIndicator style={styles.activitiesFooterIndicator} />}
|
||||
ListFooterComponent={
|
||||
loading && <ActivityIndicator style={styles.activitiesFooterIndicator} />
|
||||
}
|
||||
ListHeaderComponent={header}
|
||||
refreshControl={_refreshControl}
|
||||
onEndReached={()=>{onEndReached()}}
|
||||
onEndReached={() => {
|
||||
onEndReached();
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default ActivitiesList
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
export default ActivitiesList;
|
||||
|
@ -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:{
|
||||
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'
|
||||
textPositive: {
|
||||
color: '$primaryGreen',
|
||||
} as TextStyle,
|
||||
textNegative:{
|
||||
color: '$primaryRed'
|
||||
textNegative: {
|
||||
color: '$primaryRed',
|
||||
} as TextStyle,
|
||||
textBasicValue:{
|
||||
textBasicValue: {
|
||||
color: '$primaryBlack',
|
||||
fontWeight:'700',
|
||||
fontWeight: '700',
|
||||
fontSize: 28,
|
||||
|
||||
} as TextStyle,
|
||||
textBasicLabel:{
|
||||
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',
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
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[];
|
||||
@ -14,25 +14,23 @@ export const CoinActions = withNavigation(({ actions, onActionPress }: CoinActio
|
||||
const intl = useIntl();
|
||||
|
||||
const _renderItem = (item: string, index: number) => {
|
||||
|
||||
const _onPress = () => {
|
||||
onActionPress(item)
|
||||
}
|
||||
onActionPress(item);
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableOpacity key={`action-${item}-${index}`} style={styles.actionContainer} containerStyle={styles.actionBtnContainer} onPress={_onPress}>
|
||||
<TouchableOpacity
|
||||
key={`action-${item}-${index}`}
|
||||
style={styles.actionContainer}
|
||||
containerStyle={styles.actionBtnContainer}
|
||||
onPress={_onPress}
|
||||
>
|
||||
<Fragment>
|
||||
<Text style={styles.actionText}>
|
||||
{intl.formatMessage({ id: `wallet.${item}` })}
|
||||
</Text>
|
||||
<Text style={styles.actionText}>{intl.formatMessage({ id: `wallet.${item}` })}</Text>
|
||||
</Fragment>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.actionsContainer}>
|
||||
{actions.map(_renderItem)}
|
||||
</View>
|
||||
)
|
||||
return <View style={styles.actionsContainer}>{actions.map(_renderItem)}</View>;
|
||||
});
|
@ -1,70 +1,71 @@
|
||||
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
|
||||
onInfoPress: (id: string) => void;
|
||||
}
|
||||
|
||||
export const CoinBasics = ({ valuePairs, extraData, coinSymbol, percentChange, onInfoPress}: CoinBasicsProps) => {
|
||||
export const CoinBasics = ({
|
||||
valuePairs,
|
||||
extraData,
|
||||
coinSymbol,
|
||||
percentChange,
|
||||
onInfoPress,
|
||||
}: CoinBasicsProps) => {
|
||||
const intl = useIntl();
|
||||
const _renderCoinHeader = (
|
||||
<>
|
||||
<View style={styles.coinTitleContainer}>
|
||||
<Text style={styles.textCoinTitle}>{coinSymbol}</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={styles.textHeaderChange}>
|
||||
<Text style={styles.textHeaderChange}>
|
||||
{intl.formatMessage({ id: 'wallet.change' })}
|
||||
<Text
|
||||
style={percentChange > 0 ? styles.textPositive : styles.textNegative}>
|
||||
<Text style={percentChange > 0 ? styles.textPositive : styles.textNegative}>
|
||||
{` ${percentChange >= 0 ? '+' : ''}${percentChange.toFixed(1)}%`}
|
||||
</Text>
|
||||
|
||||
</Text>
|
||||
</>
|
||||
)
|
||||
);
|
||||
|
||||
const _renderValuePair = (args: DataPair, index: number) => {
|
||||
const label = intl.formatMessage({ id: `wallet.${args.dataKey}` })
|
||||
const label = intl.formatMessage({ id: `wallet.${args.dataKey}` });
|
||||
return (
|
||||
<Fragment key={`basic-data-${args.dataKey}-${index}`}>
|
||||
<Text style={styles.textBasicValue}>{args.value}</Text>
|
||||
<Text style={styles.textBasicLabel}>{label}</Text>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const _renderExtraData = (args: DataPair, index: number) => {
|
||||
const label = intl.formatMessage({ id: `wallet.${args.dataKey || args.labelId}` })
|
||||
const label = intl.formatMessage({ id: `wallet.${args.dataKey || args.labelId}` });
|
||||
|
||||
const _onPress = () => {
|
||||
onInfoPress(args.dataKey);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<View key={`extra-data-${args.dataKey}-${index}`} style={styles.extraDataContainer}>
|
||||
<Text
|
||||
style={[styles.textExtraLabel, args.isClickable && styles.textUnderline]}
|
||||
onPress={args.isClickable && _onPress}>
|
||||
onPress={args.isClickable && _onPress}
|
||||
>
|
||||
{label}
|
||||
</Text>
|
||||
<Text
|
||||
style={styles.textExtraValue}
|
||||
onPress={args.isClickable && _onPress}>
|
||||
<Text style={styles.textExtraValue} onPress={args.isClickable && _onPress}>
|
||||
{args.value}
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={[styles.card, styles.basicsContainer]}>
|
||||
@ -72,5 +73,5 @@ export const CoinBasics = ({ valuePairs, extraData, coinSymbol, percentChange, o
|
||||
{valuePairs.map(_renderValuePair)}
|
||||
{extraData && extraData.map(_renderExtraData)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -1,34 +1,31 @@
|
||||
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;
|
||||
@ -42,13 +39,12 @@ export const CoinChart = ({coinId}:CoinChartProps) => {
|
||||
showLabels={true}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<View style={styles.card}>
|
||||
{_renderGraph()}
|
||||
</View>
|
||||
<View style={styles.card}>{_renderGraph()}</View>
|
||||
<RangeSelector range={range} onRangeChange={_onRangeChange} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -1,17 +1,17 @@
|
||||
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 = ({
|
||||
@ -20,35 +20,29 @@ export const CoinSummary = ({
|
||||
coinData,
|
||||
percentChagne,
|
||||
onActionPress,
|
||||
onInfoPress
|
||||
}:CoinSummaryProps) => {
|
||||
const {
|
||||
balance,
|
||||
estimateValue,
|
||||
savings,
|
||||
extraDataPairs,
|
||||
actions
|
||||
} = coinData
|
||||
onInfoPress,
|
||||
}: CoinSummaryProps) => {
|
||||
const { balance, estimateValue, savings, extraDataPairs, actions } = coinData;
|
||||
|
||||
const valuePairs = [
|
||||
{
|
||||
dataKey:'amount_desc',
|
||||
value:balance
|
||||
}
|
||||
] as DataPair[]
|
||||
dataKey: 'amount_desc',
|
||||
value: balance,
|
||||
},
|
||||
] as DataPair[];
|
||||
|
||||
if(estimateValue !== undefined){
|
||||
if (estimateValue !== undefined) {
|
||||
valuePairs.push({
|
||||
dataKey:'estimated_value',
|
||||
value:<FormattedCurrency isApproximate isToken value={estimateValue} />,
|
||||
})
|
||||
dataKey: 'estimated_value',
|
||||
value: <FormattedCurrency isApproximate isToken value={estimateValue} />,
|
||||
});
|
||||
}
|
||||
|
||||
if(savings !== undefined){
|
||||
if (savings !== undefined) {
|
||||
valuePairs.push({
|
||||
dataKey:'savings',
|
||||
value:savings
|
||||
})
|
||||
dataKey: 'savings',
|
||||
value: savings,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
@ -60,10 +54,8 @@ export const CoinSummary = ({
|
||||
percentChange={percentChagne}
|
||||
onInfoPress={onInfoPress}
|
||||
/>
|
||||
<CoinActions actions={actions} onActionPress={onActionPress}/>
|
||||
{
|
||||
id !== COIN_IDS.ECENCY && id !== COIN_IDS.HP && <CoinChart coinId={id} />
|
||||
}
|
||||
<CoinActions actions={actions} onActionPress={onActionPress} />
|
||||
{id !== COIN_IDS.ECENCY && id !== COIN_IDS.HP && <CoinChart coinId={id} />}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
@ -1,18 +1,18 @@
|
||||
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',
|
||||
@ -25,13 +25,13 @@ interface DelegationItem {
|
||||
timestamp: string;
|
||||
}
|
||||
|
||||
export const DelegationsModal = forwardRef(({ }, ref) => {
|
||||
export const DelegationsModal = forwardRef(({}, ref) => {
|
||||
const intl = useIntl();
|
||||
const navigation = useNavigation<StackNavigationProp<any>>();
|
||||
|
||||
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<DelegationItem[]>([]);
|
||||
const [showModal, setShowModal] = useState(false);
|
||||
@ -40,51 +40,50 @@ export const DelegationsModal = forwardRef(({ }, ref) => {
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
showModal: (_mode: MODES) => {
|
||||
setDelegations([])
|
||||
setShowModal(true)
|
||||
setMode(_mode)
|
||||
}
|
||||
}))
|
||||
setDelegations([]);
|
||||
setShowModal(true);
|
||||
setMode(_mode);
|
||||
},
|
||||
}));
|
||||
|
||||
useEffect(() => {
|
||||
if (showModal) {
|
||||
_getDelegations()
|
||||
_getDelegations();
|
||||
}
|
||||
}, [mode, showModal])
|
||||
|
||||
}, [mode, showModal]);
|
||||
|
||||
const _getVestingDelegations = async (startUsername: string = '') => {
|
||||
let resData:any = []
|
||||
let resData: any = [];
|
||||
let limit = 1000;
|
||||
|
||||
const response = await getVestingDelegations(currentAccount.username, startUsername, limit);
|
||||
resData = response.map((item) => ({
|
||||
resData = response.map(
|
||||
(item) =>
|
||||
({
|
||||
username: item.delegatee,
|
||||
vestingShares: item.vesting_shares,
|
||||
timestamp: item.min_delegation_time
|
||||
} as DelegationItem))
|
||||
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')
|
||||
const data = await _getVestingDelegations(response[response.length - 1].delegatee);
|
||||
resData = unionBy(resData, data, 'username');
|
||||
}
|
||||
|
||||
|
||||
return resData;
|
||||
}
|
||||
};
|
||||
|
||||
const _getReceivedDelegations = async () => {
|
||||
const response = await getReceivedVestingShares(currentAccount.username)
|
||||
const response = await getReceivedVestingShares(currentAccount.username);
|
||||
return response.map((item) => ({
|
||||
username: item.delegator,
|
||||
vestingShares: item.vesting_shares,
|
||||
timestamp: item.timestamp
|
||||
}))
|
||||
}
|
||||
|
||||
timestamp: item.timestamp,
|
||||
}));
|
||||
};
|
||||
|
||||
const _getDelegations = async () => {
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
let response: DelegationItem[] = [];
|
||||
@ -99,26 +98,24 @@ export const DelegationsModal = forwardRef(({ }, ref) => {
|
||||
setDelegations(response);
|
||||
setIsLoading(false);
|
||||
} catch (err) {
|
||||
console.warn("Failed to get delegations", err)
|
||||
console.warn('Failed to get delegations', err);
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
const _handleOnUserPress = (username:string) => {
|
||||
const _handleOnUserPress = (username: string) => {
|
||||
navigation.navigate({
|
||||
name: ROUTES.SCREENS.PROFILE,
|
||||
params: {
|
||||
username,
|
||||
},
|
||||
key: username
|
||||
key: username,
|
||||
});
|
||||
setShowModal(false);
|
||||
};
|
||||
|
||||
const _handleOnPressUpdate = (username:string) => {
|
||||
if(mode === MODES.DELEGATEED){
|
||||
const _handleOnPressUpdate = (username: string) => {
|
||||
if (mode === MODES.DELEGATEED) {
|
||||
console.log('delegate HP!');
|
||||
navigation.navigate({
|
||||
name: ROUTES.SCREENS.TRANSFER,
|
||||
@ -130,14 +127,15 @@ export const DelegationsModal = forwardRef(({ }, ref) => {
|
||||
});
|
||||
setShowModal(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const title = intl.formatMessage({ id: `wallet.${mode}` })
|
||||
const title = intl.formatMessage({ id: `wallet.${mode}` });
|
||||
|
||||
const _renderItem = ({ item, index }: { item: DelegationItem, index: number }) => {
|
||||
const _renderItem = ({ item, index }: { item: DelegationItem; index: number }) => {
|
||||
const value = vestsToHp(item.vestingShares, globalProps.hivePerMVests).toFixed(3) + ' HP';
|
||||
const timeString = new Date(item.timestamp).toDateString();
|
||||
const subRightText = mode === MODES.DELEGATEED && intl.formatMessage({id:"wallet.tap_update"})
|
||||
const subRightText =
|
||||
mode === MODES.DELEGATEED && intl.formatMessage({ id: 'wallet.tap_update' });
|
||||
|
||||
return (
|
||||
<UserListItem
|
||||
@ -150,13 +148,11 @@ export const DelegationsModal = forwardRef(({ }, ref) => {
|
||||
subRightText={subRightText}
|
||||
isLoggedIn
|
||||
handleOnPress={() => _handleOnUserPress(item.username)}
|
||||
onPressRightText={()=>_handleOnPressUpdate(item.username)}
|
||||
onPressRightText={() => _handleOnPressUpdate(item.username)}
|
||||
isClickable
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
const _renderContent = () => {
|
||||
return (
|
||||
@ -166,7 +162,9 @@ export const DelegationsModal = forwardRef(({ }, ref) => {
|
||||
<BasicHeader
|
||||
backIconName="close"
|
||||
isModalHeader
|
||||
handleOnPressClose={() => { setShowModal(false) }}
|
||||
handleOnPressClose={() => {
|
||||
setShowModal(false);
|
||||
}}
|
||||
title={`${title} (${data && data.length})`}
|
||||
isHasSearch
|
||||
handleOnSearch={(text) => handleSearch(text, 'username')}
|
||||
@ -189,10 +187,9 @@ export const DelegationsModal = forwardRef(({ }, ref) => {
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
</AccountListContainer>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@ -206,5 +203,5 @@ export const DelegationsModal = forwardRef(({ }, ref) => {
|
||||
>
|
||||
{_renderContent()}
|
||||
</Modal>
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
@ -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) => {
|
||||
|
||||
const _onSelection = (range:number) => {
|
||||
console.log('selection', range)
|
||||
export const RangeSelector = ({ range, onRangeChange }: RangeSelectorProps) => {
|
||||
const _onSelection = (range: number) => {
|
||||
console.log('selection', range);
|
||||
onRangeChange(range);
|
||||
//TODO: implement on range change prop
|
||||
}
|
||||
};
|
||||
|
||||
const _renderRangeButtons = FILTERS.map((item:RangeOption)=>(
|
||||
<TouchableOpacity key={`range option-${item.value}`} onPress={()=>_onSelection(item.value)} >
|
||||
<View style={{
|
||||
const _renderRangeButtons = FILTERS.map((item: RangeOption) => (
|
||||
<TouchableOpacity key={`range option-${item.value}`} onPress={() => _onSelection(item.value)}>
|
||||
<View
|
||||
style={{
|
||||
...styles.rangeOptionWrapper,
|
||||
backgroundColor: EStyleSheet.value(
|
||||
item.value === range ?
|
||||
'$darkGrayBackground':'$primaryLightBackground'
|
||||
)
|
||||
}}>
|
||||
<Text style={{
|
||||
item.value === range ? '$darkGrayBackground' : '$primaryLightBackground',
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={{
|
||||
...styles.textRange,
|
||||
color: EStyleSheet.value(
|
||||
item.value === range ?
|
||||
'$white':'$primaryDarkText'
|
||||
)
|
||||
}}>
|
||||
color: EStyleSheet.value(item.value === range ? '$white' : '$primaryDarkText'),
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
))
|
||||
));
|
||||
|
||||
return (
|
||||
<View style={[styles.card, styles.rangeContainer]}>
|
||||
{_renderRangeButtons}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
return <View style={[styles.card, styles.rangeContainer]}>{_renderRangeButtons}</View>;
|
||||
};
|
||||
|
||||
const FILTERS = [
|
||||
{
|
||||
label:'24H',
|
||||
value:1
|
||||
label: '24H',
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label:'1W',
|
||||
value:7
|
||||
label: '1W',
|
||||
value: 7,
|
||||
},
|
||||
{
|
||||
label:'1M',
|
||||
value:20
|
||||
label: '1M',
|
||||
value: 20,
|
||||
},
|
||||
{
|
||||
label:'1Y',
|
||||
value:365
|
||||
label: '1Y',
|
||||
value: 365,
|
||||
},
|
||||
{
|
||||
label:'5Y',
|
||||
value:365*5
|
||||
label: '5Y',
|
||||
value: 365 * 5,
|
||||
},
|
||||
] as RangeOption[]
|
||||
] as RangeOption[];
|
||||
|
@ -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 = (
|
||||
<CoinSummary
|
||||
@ -165,9 +177,9 @@ const CoinDetailsScreen = ({ navigation, route }: CoinDetailsScreenProps) => {
|
||||
coinData={coinData}
|
||||
percentChagne={quote.percentChange || 0}
|
||||
onActionPress={_onActionPress}
|
||||
onInfoPress={_onInfoPress} />
|
||||
)
|
||||
|
||||
onInfoPress={_onInfoPress}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
@ -183,7 +195,7 @@ const CoinDetailsScreen = ({ navigation, route }: CoinDetailsScreenProps) => {
|
||||
/>
|
||||
<DelegationsModal ref={delegationsModalRef} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default CoinDetailsScreen
|
||||
export default CoinDetailsScreen;
|
||||
|
@ -2,9 +2,7 @@ import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
container: {
|
||||
flex:1,
|
||||
flex: 1,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
|
@ -1,23 +1,15 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import {
|
||||
Alert,
|
||||
import React, { Fragment, useEffect, useState } from 'react';
|
||||
|
||||
FlatList,
|
||||
ScrollView,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
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 = () => (
|
||||
<View style={styles.versionsListContainer}>
|
||||
<FlatList
|
||||
@ -160,7 +145,7 @@ const EditHistoryScreen = ({ route }) => {
|
||||
<View style={styles.diffContainer}>
|
||||
<AutoHeightWebView source={{ html: item.titleDiff }} customStyle={customTitleStyle} />
|
||||
<View style={styles.tagsContainer}>
|
||||
<Icon style={styles.tagIcon} iconType="AntDesign" name={'tag'} />
|
||||
<Icon style={styles.tagIcon} iconType="AntDesign" name="tag" />
|
||||
<AutoHeightWebView source={{ html: item.tagsDiff }} customStyle={customTagsStyle} />
|
||||
</View>
|
||||
<AutoHeightWebView source={{ html: item.bodyDiff }} customStyle={customBodyStyle} />
|
||||
@ -168,7 +153,6 @@ const EditHistoryScreen = ({ route }) => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const _renderPlainBody = (selectedItem: CommentHistoryListItemDiff) => {
|
||||
return (
|
||||
<>
|
||||
@ -180,7 +164,7 @@ const EditHistoryScreen = ({ route }) => {
|
||||
editable={false}
|
||||
/>
|
||||
<View style={styles.tagsContainer}>
|
||||
<Icon style={styles.tagIcon} iconType="AntDesign" name={'tag'} />
|
||||
<Icon style={styles.tagIcon} iconType="AntDesign" name="tag" />
|
||||
<Text style={styles.tags}>{selectedItem.tags}</Text>
|
||||
</View>
|
||||
</View>
|
||||
@ -196,7 +180,6 @@ const EditHistoryScreen = ({ route }) => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
const _renderBody = () => {
|
||||
const selectedItem = editHistory.find((x) => x.v === versionSelected);
|
||||
if (!selectedItem) {
|
||||
|
@ -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',
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user