mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-11-22 23:28:56 +03:00
Merge branch 'development' of github.com:ecency/ecency-mobile into feature/accounts-bottom-sheet
This commit is contained in:
commit
8475f2c91b
@ -27,7 +27,7 @@ buildscript {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath('com.android.tools.build:gradle:3.5.2')
|
||||
classpath('com.android.tools.build:gradle:4.0.1')
|
||||
|
||||
classpath 'com.google.gms:google-services:4.3.3'
|
||||
classpath 'com.bugsnag:bugsnag-android-gradle-plugin:4.+'
|
||||
|
@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.5-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
@ -43,7 +43,7 @@
|
||||
05B6C4B024C306CE00B7FA60 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 980BC9BC0D3B4AC69645C842 /* Zocial.ttf */; };
|
||||
0A1D279E0D3CD306C889592E /* libPods-Ecency-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7093E51BBC0EE2F41AB19EBA /* libPods-Ecency-tvOS.a */; };
|
||||
1CD0B89E258019B600A7D78E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1CD0B89B258019B600A7D78E /* GoogleService-Info.plist */; };
|
||||
2B3CF3607B7CB9B7296FD5EF /* (null) in Frameworks */ = {isa = PBXBuildFile; };
|
||||
2B3CF3607B7CB9B7296FD5EF /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
|
||||
2D02E4BC1E0B4A80006451C7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
|
||||
2D02E4BD1E0B4A84006451C7 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
|
||||
2D02E4BF1E0B4AB3006451C7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
|
||||
@ -55,7 +55,7 @@
|
||||
CFAA2A599FD65F360D9B3E1E /* libPods-EcencyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B344CAA24725C973F48BE81E /* libPods-EcencyTests.a */; };
|
||||
D71EB20EDB9B987C0574BAFE /* libPods-EcencyTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C97456BE898C00B5EDA21C2E /* libPods-EcencyTests.a */; };
|
||||
DC0E25610BB5F49AFF4514AD /* libPods-Ecency.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 388DF3FF85F08109F722083B /* libPods-Ecency.a */; };
|
||||
F77F6C7E54F3C783A2773E9D /* (null) in Frameworks */ = {isa = PBXBuildFile; };
|
||||
F77F6C7E54F3C783A2773E9D /* BuildFile in Frameworks */ = {isa = PBXBuildFile; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -204,8 +204,8 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
05B6C49424C306CE00B7FA60 /* StoreKit.framework in Frameworks */,
|
||||
F77F6C7E54F3C783A2773E9D /* (null) in Frameworks */,
|
||||
2B3CF3607B7CB9B7296FD5EF /* (null) in Frameworks */,
|
||||
F77F6C7E54F3C783A2773E9D /* BuildFile in Frameworks */,
|
||||
2B3CF3607B7CB9B7296FD5EF /* BuildFile in Frameworks */,
|
||||
DC0E25610BB5F49AFF4514AD /* libPods-Ecency.a in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -752,7 +752,7 @@
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Ecency/Pods-Ecency-resources.sh",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController/QBImagePicker.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/RNImageCropPicker/QBImagePicker.bundle",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf",
|
||||
@ -769,7 +769,7 @@
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Octicons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf",
|
||||
"${PODS_ROOT}/../../node_modules/react-native-vector-icons/Fonts/Zocial.ttf",
|
||||
"${PODS_ROOT}/RSKImageCropper/RSKImageCropper/RSKImageCropperStrings.bundle",
|
||||
"${PODS_CONFIGURATION_BUILD_DIR}/TOCropViewController/TOCropViewControllerBundle.bundle",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
@ -790,7 +790,7 @@
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Octicons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/SimpleLineIcons.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Zocial.ttf",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RSKImageCropperStrings.bundle",
|
||||
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/TOCropViewControllerBundle.bundle",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
|
@ -145,7 +145,6 @@ PODS:
|
||||
- nanopb/encode (1.30905.0)
|
||||
- PromisesObjC (1.2.9)
|
||||
- Protobuf (3.12.0)
|
||||
- QBImagePickerController (3.4.0)
|
||||
- RCTRequired (0.61.5)
|
||||
- RCTTypeSafety (0.61.5):
|
||||
- FBLazyVector (= 0.61.5)
|
||||
@ -400,11 +399,15 @@ PODS:
|
||||
- React
|
||||
- RNIap (3.4.15):
|
||||
- React
|
||||
- RNImageCropPicker (0.26.2):
|
||||
- QBImagePickerController
|
||||
- RNImageCropPicker (0.35.2):
|
||||
- React-Core
|
||||
- React-RCTImage
|
||||
- RSKImageCropper
|
||||
- RNImageCropPicker/QBImagePickerController (= 0.35.2)
|
||||
- TOCropViewController
|
||||
- RNImageCropPicker/QBImagePickerController (0.35.2):
|
||||
- React-Core
|
||||
- React-RCTImage
|
||||
- TOCropViewController
|
||||
- RNReanimated (1.13.2):
|
||||
- React-Core
|
||||
- RNScreens (2.10.1):
|
||||
@ -413,13 +416,13 @@ PODS:
|
||||
- React
|
||||
- RNVectorIcons (6.7.0):
|
||||
- React
|
||||
- RSKImageCropper (2.2.3)
|
||||
- SDWebImage (5.8.4):
|
||||
- SDWebImage/Core (= 5.8.4)
|
||||
- SDWebImage/Core (5.8.4)
|
||||
- SDWebImageWebPCoder (0.6.1):
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.7)
|
||||
- TOCropViewController (2.6.0)
|
||||
- toolbar-android (0.1.0-rc.2):
|
||||
- React
|
||||
- Yoga (1.14.0)
|
||||
@ -509,10 +512,9 @@ SPEC REPOS:
|
||||
- nanopb
|
||||
- PromisesObjC
|
||||
- Protobuf
|
||||
- QBImagePickerController
|
||||
- RSKImageCropper
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
- TOCropViewController
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
appcenter-analytics:
|
||||
@ -666,7 +668,6 @@ SPEC CHECKSUMS:
|
||||
nanopb: c43f40fadfe79e8b8db116583945847910cbabc9
|
||||
PromisesObjC: b48e0338dbbac2207e611750777895f7a5811b75
|
||||
Protobuf: 2793fcd0622a00b546c60e7cbbcc493e043e9bb9
|
||||
QBImagePickerController: d54cf93db6decf26baf6ed3472f336ef35cae022
|
||||
RCTRequired: b153add4da6e7dbc44aebf93f3cf4fcae392ddf1
|
||||
RCTTypeSafety: 9aa1b91d7f9310fc6eadc3cf95126ffe818af320
|
||||
React: b6a59ef847b2b40bb6e0180a97d0ca716969ac78
|
||||
@ -707,17 +708,17 @@ SPEC CHECKSUMS:
|
||||
RNFBMessaging: 3bb7dcf398789ce359a9f6b97b83472a3090f65a
|
||||
RNGestureHandler: b6b359bb800ae399a9c8b27032bdbf7c18f08a08
|
||||
RNIap: b4c77c8bc4501203f4b743126a05da23f10f40b4
|
||||
RNImageCropPicker: 9d1a7eea4f8368fc479cbd2bf26459bd3c74d9aa
|
||||
RNImageCropPicker: 9e0bf18cf4184a846fed55747c8e622208b39947
|
||||
RNReanimated: e03f7425cb7a38dcf1b644d680d1bfc91c3337ad
|
||||
RNScreens: b748efec66e095134c7166ca333b628cd7e6f3e2
|
||||
RNSVG: 8ba35cbeb385a52fd960fd28db9d7d18b4c2974f
|
||||
RNVectorIcons: 368d6d8b8301224e5ffb6254191f4f8876c2be0d
|
||||
RSKImageCropper: a446db0e8444a036b34f3c43db01b2373baa4b2a
|
||||
SDWebImage: cf6922231e95550934da2ada0f20f2becf2ceba9
|
||||
SDWebImageWebPCoder: d0dac55073088d24b2ac1b191a71a8f8d0adac21
|
||||
TOCropViewController: 3105367e808b7d3d886a74ff59bf4804e7d3ab38
|
||||
toolbar-android: 85f3ef4d691469f2d304e7dee4bca013aa1ba1ff
|
||||
Yoga: f2a7cd4280bfe2cca5a7aed98ba0eb3d1310f18b
|
||||
|
||||
PODFILE CHECKSUM: 1f30c7da5061dbc47185442a6ab4a3c95ac48c04
|
||||
|
||||
COCOAPODS: 1.10.0
|
||||
COCOAPODS: 1.9.3
|
||||
|
@ -27,7 +27,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"@ecency/render-helper": "^2.0.11",
|
||||
"@ecency/render-helper": "^2.0.15",
|
||||
"@esteemapp/dhive": "0.15.0",
|
||||
"@esteemapp/react-native-autocomplete-input": "^4.2.1",
|
||||
"@esteemapp/react-native-modal-popover": "^0.0.15",
|
||||
@ -75,7 +75,8 @@
|
||||
"react-native-fast-image": "^8.3.2",
|
||||
"react-native-gesture-handler": "^1.4.1",
|
||||
"react-native-iap": "3.4.15",
|
||||
"react-native-image-crop-picker": "^0.26.1",
|
||||
"react-native-image-crop-picker": "^0.35.2",
|
||||
"react-native-image-size": "^1.1.3",
|
||||
"react-native-image-zoom-viewer": "^2.2.27",
|
||||
"react-native-keyboard-aware-scroll-view": "^0.9.1",
|
||||
"react-native-linear-gradient": "^2.4.2",
|
||||
|
1
src/assets/animations/empty_screen.json
Normal file
1
src/assets/animations/empty_screen.json
Normal file
File diff suppressed because one or more lines are too long
@ -11,6 +11,7 @@ import UserListItem from './view/userListItem/userListItem';
|
||||
import WalletLineItem from './view/walletLineItem/walletLineItemView';
|
||||
import CommunityListItem from './view/communityListItem/communityListItem';
|
||||
import Separator from './view/separator/separatorView';
|
||||
import EmptyScreen from './view/emptyScreen/emptyScreenView';
|
||||
|
||||
// Placeholders
|
||||
import ListItemPlaceHolder from './view/placeHolder/listItemPlaceHolderView';
|
||||
@ -48,4 +49,5 @@ export {
|
||||
WalletUnclaimedPlaceHolder,
|
||||
CommunitiesPlaceHolder,
|
||||
Separator,
|
||||
EmptyScreen,
|
||||
};
|
||||
|
@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { View, Text } from 'react-native';
|
||||
import LottieView from 'lottie-react-native';
|
||||
import globalStyles from '../../../../globalStyles';
|
||||
|
||||
const EmptyScreenView = ({ style, textStyle }) => (
|
||||
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<LottieView
|
||||
style={[{ width: 150, height: 150, marginBottom: 12 }, style]}
|
||||
source={require('../../../../assets/animations/empty_screen.json')}
|
||||
autoPlay
|
||||
loop={true}
|
||||
/>
|
||||
<Text style={[globalStyles.title, textStyle]}>Nothing found!</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
export default EmptyScreenView;
|
3
src/components/communitiesList/index.js
Normal file
3
src/components/communitiesList/index.js
Normal file
@ -0,0 +1,3 @@
|
||||
import CommunitiesList from './view/communitiesList';
|
||||
|
||||
export default CommunitiesList;
|
@ -2,23 +2,22 @@ import React from 'react';
|
||||
import { SafeAreaView, FlatList } from 'react-native';
|
||||
|
||||
// Components
|
||||
import CommunitiesListItem from './CommunitiesListItem';
|
||||
import { CommunitiesPlaceHolder } from '../../../components/basicUIElements';
|
||||
import { CommunitiesPlaceHolder } from '../../basicUIElements';
|
||||
import CommunitiesListItem from './communitiesListItem';
|
||||
|
||||
// Styles
|
||||
import styles from './communitiesListStyles';
|
||||
|
||||
const CommunitiesList = ({
|
||||
votes,
|
||||
data,
|
||||
subscribingCommunities,
|
||||
handleOnPress,
|
||||
handleSubscribeButtonPress,
|
||||
allSubscriptions,
|
||||
isLoggedIn,
|
||||
noResult,
|
||||
screen,
|
||||
}) => {
|
||||
const _renderItem = ({ item, index }) => {
|
||||
const isSubscribed = allSubscriptions.some((sub) => sub[0] === item.name);
|
||||
|
||||
return (
|
||||
<CommunitiesListItem
|
||||
index={index}
|
||||
@ -33,8 +32,13 @@ const CommunitiesList = ({
|
||||
name={item.name}
|
||||
handleOnPress={handleOnPress}
|
||||
handleSubscribeButtonPress={handleSubscribeButtonPress}
|
||||
isSubscribed={isSubscribed}
|
||||
isSubscribed={item.isSubscribed}
|
||||
isLoggedIn={isLoggedIn}
|
||||
loading={
|
||||
subscribingCommunities.hasOwnProperty(item.name) &&
|
||||
subscribingCommunities[item.name].loading
|
||||
}
|
||||
screen={screen}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -57,8 +61,8 @@ const CommunitiesList = ({
|
||||
<SafeAreaView style={styles.container}>
|
||||
{!noResult && (
|
||||
<FlatList
|
||||
data={votes}
|
||||
keyExtractor={(item) => item.id && item.id.toString()}
|
||||
data={data}
|
||||
keyExtractor={(item, index) => index.toString()}
|
||||
renderItem={_renderItem}
|
||||
ListEmptyComponent={_renderEmptyContent}
|
||||
/>
|
@ -0,0 +1,3 @@
|
||||
import CommunitiesListItem from './view/CommunitiesListItem';
|
||||
|
||||
export default CommunitiesListItem;
|
@ -1,12 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import { View, Text, TouchableOpacity } from 'react-native';
|
||||
import { View, Text, TouchableOpacity, ActivityIndicator } from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import styles from './communitiesListItemStyles';
|
||||
|
||||
import { Tag } from '../../../components/basicUIElements';
|
||||
import { Tag } from '../../../../basicUIElements';
|
||||
|
||||
const UserListItem = ({
|
||||
const CommunitiesListItem = ({
|
||||
index,
|
||||
handleOnPress,
|
||||
handleOnLongPress,
|
||||
@ -22,14 +22,13 @@ const UserListItem = ({
|
||||
handleSubscribeButtonPress,
|
||||
isSubscribed,
|
||||
isLoggedIn,
|
||||
loading,
|
||||
screen,
|
||||
}) => {
|
||||
const [subscribed, setSubscribed] = useState(isSubscribed);
|
||||
const intl = useIntl();
|
||||
|
||||
const _handleSubscribeButtonPress = () => {
|
||||
handleSubscribeButtonPress({ subscribed: !subscribed, communityId: name }).then(() => {
|
||||
setSubscribed(!subscribed);
|
||||
});
|
||||
handleSubscribeButtonPress({ isSubscribed: isSubscribed, communityId: name }, screen);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -41,12 +40,17 @@ const UserListItem = ({
|
||||
<View style={styles.content}>
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>{title}</Text>
|
||||
{isLoggedIn && (
|
||||
{isLoggedIn &&
|
||||
(loading ? (
|
||||
<View style={styles.indicatorView}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
) : (
|
||||
<Tag
|
||||
style={styles.subscribeButton}
|
||||
textStyle={subscribed && styles.subscribeButtonText}
|
||||
textStyle={isSubscribed && styles.subscribeButtonText}
|
||||
value={
|
||||
!subscribed
|
||||
!isSubscribed
|
||||
? intl.formatMessage({
|
||||
id: 'search_result.communities.subscribe',
|
||||
})
|
||||
@ -54,11 +58,11 @@ const UserListItem = ({
|
||||
id: 'search_result.communities.unsubscribe',
|
||||
})
|
||||
}
|
||||
isPin={!subscribed}
|
||||
isPin={!isSubscribed}
|
||||
isFilter
|
||||
onPress={_handleSubscribeButtonPress}
|
||||
/>
|
||||
)}
|
||||
))}
|
||||
</View>
|
||||
{!!about && <Text style={styles.about}>{about}</Text>}
|
||||
<View style={styles.separator} />
|
||||
@ -77,4 +81,4 @@ const UserListItem = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default UserListItem;
|
||||
export default CommunitiesListItem;
|
@ -59,4 +59,9 @@ export default EStyleSheet.create({
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
},
|
||||
indicatorView: {
|
||||
width: 65,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
});
|
@ -34,6 +34,7 @@ import { PostForm } from './postForm';
|
||||
import { PostHeaderDescription, PostBody, Tags } from './postElements';
|
||||
import { PostListItem } from './postListItem';
|
||||
import { ProfileSummary } from './profileSummary';
|
||||
import { ProgressiveImage } from './progressiveImage';
|
||||
|
||||
import { SearchInput } from './searchInput';
|
||||
import { SearchModal } from './searchModal';
|
||||
@ -64,6 +65,8 @@ import ScaleSlider from './scaleSlider/scaleSliderView';
|
||||
import { ProductItemLine } from './productItemLine/productItemLineView';
|
||||
import { HorizontalIconList } from './horizontalIconList/horizontalIconListView';
|
||||
import { PopoverWrapper } from './popoverWrapper/popoverWrapperView';
|
||||
import CommunitiesList from './communitiesList';
|
||||
import SubscribedCommunitiesList from './subscribedCommunitiesList';
|
||||
|
||||
// View
|
||||
import { Comment } from './comment';
|
||||
@ -104,6 +107,7 @@ import {
|
||||
WalletLineItem,
|
||||
WalletUnclaimedPlaceHolder,
|
||||
Separator,
|
||||
EmptyScreen,
|
||||
} from './basicUIElements';
|
||||
|
||||
export {
|
||||
@ -207,6 +211,9 @@ export {
|
||||
WalletLineItem,
|
||||
WalletUnclaimedPlaceHolder,
|
||||
Separator,
|
||||
EmptyScreen,
|
||||
HorizontalIconList,
|
||||
PopoverWrapper,
|
||||
CommunitiesList,
|
||||
SubscribedCommunitiesList,
|
||||
};
|
||||
|
@ -44,6 +44,7 @@ const MarkdownEditorView = ({
|
||||
const [text, setText] = useState(draftBody || '');
|
||||
const [selection, setSelection] = useState({ start: 0, end: 0 });
|
||||
const [editable, setEditable] = useState(true);
|
||||
const [height, setHeight] = useState(0);
|
||||
|
||||
const inputRef = useRef(null);
|
||||
const galleryRef = useRef(null);
|
||||
@ -260,7 +261,7 @@ const MarkdownEditorView = ({
|
||||
<TextInput
|
||||
multiline
|
||||
autoCorrect={true}
|
||||
autoFocus={false}
|
||||
autoFocus={isReply ? true : false}
|
||||
onChangeText={_changeText}
|
||||
onSelectionChange={_handleOnSelectionChange}
|
||||
placeholder={intl.formatMessage({
|
||||
|
@ -32,8 +32,8 @@ export default EStyleSheet.create({
|
||||
margin: 0,
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center',
|
||||
height: 200,
|
||||
width: '$deviceWidth - 16',
|
||||
//height: 200,
|
||||
//width: '$deviceWidth - 16',
|
||||
borderRadius: 8,
|
||||
backgroundColor: '$primaryLightGray',
|
||||
},
|
||||
|
@ -1,8 +1,8 @@
|
||||
import React, { Component, useState, useEffect } from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { TouchableOpacity, Text, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import { TouchableOpacity, Text, View, Dimensions } from 'react-native';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import ImageSize from 'react-native-image-size';
|
||||
|
||||
// Utils
|
||||
import { getTimeFromNow } from '../../../utils/time';
|
||||
@ -18,8 +18,13 @@ import { Upvote } from '../../upvote';
|
||||
import styles from './postCardStyles';
|
||||
|
||||
// Defaults
|
||||
import DEFAULT_IMAGE from '../../../assets/no_image.png';
|
||||
import NSFW_IMAGE from '../../../assets/nsfw.png';
|
||||
import ProgressiveImage from '../../progressiveImage';
|
||||
|
||||
const dim = Dimensions.get('window');
|
||||
const DEFAULT_IMAGE =
|
||||
'https://images.ecency.com/DQmT8R33geccEjJfzZEdsRHpP3VE8pu3peRCnQa1qukU4KR/no_image_3x.png';
|
||||
const NSFW_IMAGE =
|
||||
'https://images.ecency.com/DQmZ1jW4p7o5GyoqWyCib1fSLE2ftbewsMCt2GvbmT9kmoY/nsfw_3x.png';
|
||||
|
||||
const PostCardView = ({
|
||||
handleOnUserPress,
|
||||
@ -36,6 +41,7 @@ const PostCardView = ({
|
||||
}) => {
|
||||
const [rebloggedBy, setRebloggedBy] = useState(get(content, 'reblogged_by[0]', null));
|
||||
const [activeVot, setActiveVot] = useState(activeVotes);
|
||||
const [calcImgHeight, setCalcImgHeight] = useState(300);
|
||||
//console.log(activeVotes);
|
||||
// Component Functions
|
||||
|
||||
@ -62,11 +68,16 @@ const PostCardView = ({
|
||||
const _getPostImage = (content, isNsfwPost) => {
|
||||
if (content && content.image) {
|
||||
if (isNsfwPost && content.nsfw) {
|
||||
return NSFW_IMAGE;
|
||||
return { image: NSFW_IMAGE, thumbnail: NSFW_IMAGE };
|
||||
}
|
||||
return { uri: content.image, priority: FastImage.priority.high };
|
||||
//console.log(content)
|
||||
ImageSize.getSize(content.image).then((size) => {
|
||||
setCalcImgHeight((size.height / size.width) * dim.width);
|
||||
});
|
||||
return { image: content.image, thumbnail: content.thumbnail };
|
||||
} else {
|
||||
return { image: DEFAULT_IMAGE, thumbnail: DEFAULT_IMAGE };
|
||||
}
|
||||
return DEFAULT_IMAGE;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@ -102,11 +113,13 @@ const PostCardView = ({
|
||||
<View style={styles.postBodyWrapper}>
|
||||
<TouchableOpacity style={styles.hiddenImages} onPress={_handleOnContentPress}>
|
||||
{!isHideImage && (
|
||||
<FastImage
|
||||
source={_image}
|
||||
resizeMode={FastImage.resizeMode.contain}
|
||||
style={styles.thumbnail}
|
||||
defaultSource={DEFAULT_IMAGE}
|
||||
<ProgressiveImage
|
||||
source={{ uri: _image.image }}
|
||||
thumbnailSource={{ uri: _image.thumbnail }}
|
||||
style={[
|
||||
styles.thumbnail,
|
||||
{ width: dim.width - 16, height: Math.min(calcImgHeight, dim.height) },
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
<View style={[styles.postDescripton]}>
|
||||
|
@ -18,8 +18,8 @@ export default EStyleSheet.create({
|
||||
margin: 0,
|
||||
alignItems: 'center',
|
||||
alignSelf: 'center',
|
||||
height: 200,
|
||||
width: '$deviceWidth - 16',
|
||||
//height: 200,
|
||||
//width: '$deviceWidth - 16',
|
||||
borderRadius: 8,
|
||||
backgroundColor: '$primaryLightGray',
|
||||
// paddingVertical: 10,
|
||||
|
@ -1,8 +1,8 @@
|
||||
import React, { useRef, Fragment } from 'react';
|
||||
import React, { useRef, useState, useEffect, Fragment } from 'react';
|
||||
import ActionSheet from 'react-native-actionsheet';
|
||||
import { View, Text, TouchableOpacity } from 'react-native';
|
||||
import { View, Text, TouchableOpacity, Dimensions } from 'react-native';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import ImageSize from 'react-native-image-size';
|
||||
|
||||
// Utils
|
||||
import { getTimeFromNow } from '../../../utils/time';
|
||||
@ -10,13 +10,17 @@ import { getTimeFromNow } from '../../../utils/time';
|
||||
// Components
|
||||
import { PostHeaderDescription } from '../../postElements';
|
||||
import { IconButton } from '../../iconButton';
|
||||
|
||||
// Defaults
|
||||
import DEFAULT_IMAGE from '../../../assets/no_image.png';
|
||||
import ProgressiveImage from '../../progressiveImage';
|
||||
|
||||
// Styles
|
||||
import styles from './postListItemStyles';
|
||||
|
||||
// Defaults
|
||||
const DEFAULT_IMAGE =
|
||||
'https://images.ecency.com/DQmT8R33geccEjJfzZEdsRHpP3VE8pu3peRCnQa1qukU4KR/no_image_3x.png';
|
||||
|
||||
const dim = Dimensions.get('window');
|
||||
|
||||
const PostListItemView = ({
|
||||
title,
|
||||
summary,
|
||||
@ -25,6 +29,7 @@ const PostListItemView = ({
|
||||
reputation,
|
||||
created,
|
||||
image,
|
||||
thumbnail,
|
||||
handleOnPressItem,
|
||||
handleOnRemoveItem,
|
||||
id,
|
||||
@ -32,9 +37,21 @@ const PostListItemView = ({
|
||||
isFormatedDate,
|
||||
}) => {
|
||||
const actionSheet = useRef(null);
|
||||
|
||||
const [calcImgHeight, setCalcImgHeight] = useState(300);
|
||||
// Component Life Cycles
|
||||
|
||||
useEffect(() => {
|
||||
let _isMounted = false;
|
||||
if (image) {
|
||||
if (!_isMounted) {
|
||||
ImageSize.getSize(image.uri).then((size) => {
|
||||
setCalcImgHeight((size.height / size.width) * dim.width);
|
||||
});
|
||||
}
|
||||
}
|
||||
return () => {
|
||||
_isMounted = true;
|
||||
};
|
||||
}, []);
|
||||
// Component Functions
|
||||
|
||||
return (
|
||||
@ -60,7 +77,14 @@ const PostListItemView = ({
|
||||
</View>
|
||||
<View style={styles.body}>
|
||||
<TouchableOpacity onPress={() => handleOnPressItem(id)}>
|
||||
<FastImage source={image} style={styles.image} defaultSource={DEFAULT_IMAGE} />
|
||||
<ProgressiveImage
|
||||
source={image}
|
||||
thumbnailSource={thumbnail}
|
||||
style={[
|
||||
styles.thumbnail,
|
||||
{ width: dim.width - 16, height: Math.min(calcImgHeight, dim.height) },
|
||||
]}
|
||||
/>
|
||||
<View style={[styles.postDescripton]}>
|
||||
<Text style={styles.title}>{title}</Text>
|
||||
<Text style={styles.summary}>{summary}</Text>
|
||||
|
@ -462,7 +462,9 @@ const PostsContainer = ({
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(subscribeAction(currentAccount, pinCode, data, successToastText, failToastText));
|
||||
dispatch(
|
||||
subscribeAction(currentAccount, pinCode, data, successToastText, failToastText, 'feedScreen'),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
|
57
src/components/progressiveImage/index.js
Normal file
57
src/components/progressiveImage/index.js
Normal file
@ -0,0 +1,57 @@
|
||||
import React from 'react';
|
||||
import { View, StyleSheet, Animated } from 'react-native';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
imageOverlay: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
top: 0,
|
||||
},
|
||||
container: {
|
||||
backgroundColor: '#f6f6f6',
|
||||
},
|
||||
});
|
||||
|
||||
class ProgressiveImage extends React.Component {
|
||||
thumbnailAnimated = new Animated.Value(0);
|
||||
|
||||
imageAnimated = new Animated.Value(0);
|
||||
|
||||
handleThumbnailLoad = () => {
|
||||
Animated.timing(this.thumbnailAnimated, {
|
||||
toValue: 1,
|
||||
}).start();
|
||||
};
|
||||
|
||||
onImageLoad = () => {
|
||||
Animated.timing(this.imageAnimated, {
|
||||
toValue: 1,
|
||||
}).start();
|
||||
};
|
||||
|
||||
render() {
|
||||
const { thumbnailSource, source, style, ...props } = this.props;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Animated.Image
|
||||
{...props}
|
||||
source={thumbnailSource}
|
||||
style={[style, { opacity: this.thumbnailAnimated }]}
|
||||
onLoad={this.handleThumbnailLoad}
|
||||
blurRadius={1}
|
||||
/>
|
||||
<Animated.Image
|
||||
{...props}
|
||||
source={source}
|
||||
style={[styles.imageOverlay, { opacity: this.imageAnimated }, style]}
|
||||
onLoad={this.onImageLoad}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default ProgressiveImage;
|
4
src/components/subscribedCommunitiesList/index.js
Normal file
4
src/components/subscribedCommunitiesList/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
import SubscribedCommunitiesListView from './view/subscribedCommunitiesListView';
|
||||
import SubscribedCommunitiesList from './view/subscribedCommunitiesListView';
|
||||
|
||||
export default SubscribedCommunitiesList;
|
@ -0,0 +1,51 @@
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
},
|
||||
itemWrapper: {
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 16,
|
||||
paddingBottom: 8,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
itemWrapperGray: {
|
||||
backgroundColor: '$primaryLightBackground',
|
||||
},
|
||||
username: {
|
||||
marginLeft: 10,
|
||||
color: '$primaryBlack',
|
||||
},
|
||||
communityWrapper: {
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
},
|
||||
subscribeButton: {
|
||||
maxWidth: 75,
|
||||
borderWidth: 1,
|
||||
borderColor: '$primaryBlue',
|
||||
},
|
||||
subscribeButtonText: {
|
||||
textAlign: 'center',
|
||||
color: '$primaryBlue',
|
||||
},
|
||||
community: {
|
||||
justifyContent: 'center',
|
||||
marginLeft: 15,
|
||||
color: '$primaryBlack',
|
||||
},
|
||||
tabbarItem: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
@ -0,0 +1,82 @@
|
||||
import React from 'react';
|
||||
import { View, FlatList, TouchableOpacity, Text, ActivityIndicator } from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import { Tag, UserAvatar } from '../../index';
|
||||
import { ListPlaceHolder } from '../../basicUIElements';
|
||||
|
||||
import DEFAULT_IMAGE from '../../../assets/no_image.png';
|
||||
|
||||
import styles from './subscribedCommunitiesListStyles';
|
||||
|
||||
const SubscribedCommunitiesListView = ({
|
||||
data,
|
||||
subscribingCommunities,
|
||||
handleOnPress,
|
||||
handleSubscribeButtonPress,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const _renderEmptyContent = () => {
|
||||
return (
|
||||
<>
|
||||
<ListPlaceHolder />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
data={data}
|
||||
keyExtractor={(item, index) => index.toString()}
|
||||
renderItem={({ item, index }) => (
|
||||
<View style={[styles.communityWrapper, index % 2 !== 0 && styles.itemWrapperGray]}>
|
||||
<View style={{ flex: 3, flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TouchableOpacity onPress={() => handleOnPress(item[0])}>
|
||||
<UserAvatar username={item[0]} defaultSource={DEFAULT_IMAGE} noAction />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => handleOnPress(item[0])}>
|
||||
<Text style={styles.community}>{item[1]}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View>
|
||||
{subscribingCommunities.hasOwnProperty(item[0]) &&
|
||||
subscribingCommunities[item[0]].loading ? (
|
||||
<View style={{ width: 65, alignItems: 'center', justifyContent: 'center' }}>
|
||||
<ActivityIndicator />
|
||||
</View>
|
||||
) : (
|
||||
<Tag
|
||||
style={styles.subscribeButton}
|
||||
textStyle={item[4] && styles.subscribeButtonText}
|
||||
value={
|
||||
!item[4]
|
||||
? intl.formatMessage({
|
||||
id: 'search_result.communities.subscribe',
|
||||
})
|
||||
: intl.formatMessage({
|
||||
id: 'search_result.communities.unsubscribe',
|
||||
})
|
||||
}
|
||||
isPin={!item[4]}
|
||||
isFilter
|
||||
onPress={() =>
|
||||
handleSubscribeButtonPress(
|
||||
{
|
||||
isSubscribed: item[4],
|
||||
communityId: item[0],
|
||||
},
|
||||
'communitiesScreenJoinedTab',
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
ListEmptyComponent={_renderEmptyContent}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubscribedCommunitiesListView;
|
@ -87,23 +87,22 @@ class UpvoteContainer extends PureComponent {
|
||||
const quote = get(globalProps, 'quote', 0);
|
||||
const sbdPrintRate = get(globalProps, 'sbdPrintRate', 0);
|
||||
const SBD_PRINT_RATE_MAX = 10000;
|
||||
const percent_steem_dollars =
|
||||
(content.percent_hbd || content.percent_steem_dollars || 10000) / 20000;
|
||||
const percent_steem_dollars = (content.percent_hbd || 10000) / 20000;
|
||||
|
||||
const pending_payout_sbd = pendingPayout * percent_steem_dollars;
|
||||
const pending_payout_hbd = pendingPayout * percent_steem_dollars;
|
||||
const price_per_steem = base / quote;
|
||||
|
||||
const pending_payout_sp = (pendingPayout - pending_payout_sbd) / price_per_steem;
|
||||
const pending_payout_printed_sbd = pending_payout_sbd * (sbdPrintRate / SBD_PRINT_RATE_MAX);
|
||||
const pending_payout_printed_steem =
|
||||
(pending_payout_sbd - pending_payout_printed_sbd) / price_per_steem;
|
||||
const pending_payout_hp = (pendingPayout - pending_payout_hbd) / price_per_steem;
|
||||
const pending_payout_printed_hbd = pending_payout_hbd * (sbdPrintRate / SBD_PRINT_RATE_MAX);
|
||||
const pending_payout_printed_hive =
|
||||
(pending_payout_hbd - pending_payout_printed_hbd) / price_per_steem;
|
||||
|
||||
const breakdownPayout =
|
||||
pending_payout_printed_sbd.toFixed(3) +
|
||||
pending_payout_printed_hbd.toFixed(3) +
|
||||
' HBD, ' +
|
||||
pending_payout_printed_steem.toFixed(3) +
|
||||
pending_payout_printed_hive.toFixed(3) +
|
||||
' HIVE, ' +
|
||||
pending_payout_sp.toFixed(3) +
|
||||
pending_payout_hp.toFixed(3) +
|
||||
' HP';
|
||||
|
||||
return (
|
||||
|
@ -252,6 +252,7 @@
|
||||
"schedules": "Schedules",
|
||||
"gallery": "Gallery",
|
||||
"settings": "Settings",
|
||||
"communities": "Communities",
|
||||
"add_account": "Add Account",
|
||||
"logout": "Logout",
|
||||
"cancel": "Cancel",
|
||||
@ -549,7 +550,7 @@
|
||||
"title": "Topics"
|
||||
},
|
||||
"communities": {
|
||||
"title": "Communities",
|
||||
"title": "Groups",
|
||||
"subscribe": "Join",
|
||||
"unsubscribe": "Leave",
|
||||
"subscribers": "Members",
|
||||
@ -580,5 +581,9 @@
|
||||
"user": {
|
||||
"follow": "Follow",
|
||||
"unfollow": "Unfollow"
|
||||
},
|
||||
"communities": {
|
||||
"joined": "Membership",
|
||||
"discover": "Discover"
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ export default {
|
||||
COMMENTS: `Comments${SCREEN_SUFFIX}`,
|
||||
ACCOUNT_BOOST: `AccountBoost${SCREEN_SUFFIX}`,
|
||||
COMMUNITY: `Community${SCREEN_SUFFIX}`,
|
||||
COMMUNITIES: `Communities${SCREEN_SUFFIX}`,
|
||||
},
|
||||
DRAWER: {
|
||||
MAIN: `Main${DRAWER_SUFFIX}`,
|
||||
|
@ -25,6 +25,12 @@ const authMenuItems = [
|
||||
// icon: 'photo-library',
|
||||
// id: 'gallery',
|
||||
// },
|
||||
{
|
||||
name: 'Communities',
|
||||
route: ROUTES.SCREENS.COMMUNITIES,
|
||||
icon: 'people',
|
||||
id: 'communities',
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
route: ROUTES.SCREENS.SETTINGS,
|
||||
|
@ -144,9 +144,9 @@ const WalletContainer = ({
|
||||
|
||||
const _isHasUnclaimedRewards = (account) => {
|
||||
return (
|
||||
parseToken(get(account, 'reward_steem_balance', account.reward_hive_balance)) > 0 ||
|
||||
parseToken(get(account, 'reward_sbd_balance', account.reward_hbd_balance)) > 0 ||
|
||||
parseToken(get(account, 'reward_vesting_steem', account.reward_vesting_hive)) > 0
|
||||
parseToken(get(account, 'reward_hive_balance')) > 0 ||
|
||||
parseToken(get(account, 'reward_hbd_balance')) > 0 ||
|
||||
parseToken(get(account, 'reward_vesting_hive')) > 0
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -37,6 +37,7 @@ import {
|
||||
AccountBoost,
|
||||
TagResult,
|
||||
Community,
|
||||
Communities,
|
||||
} from '../screens';
|
||||
|
||||
const bottomTabNavigator = createBottomTabNavigator(
|
||||
@ -148,6 +149,7 @@ const stackNavigator = createStackNavigator(
|
||||
[ROUTES.SCREENS.SPIN_GAME]: { screen: SpinGame },
|
||||
[ROUTES.SCREENS.ACCOUNT_BOOST]: { screen: AccountBoost },
|
||||
[ROUTES.SCREENS.COMMUNITY]: { screen: Community },
|
||||
[ROUTES.SCREENS.COMMUNITIES]: { screen: Communities },
|
||||
},
|
||||
{
|
||||
headerMode: 'none',
|
||||
|
@ -86,12 +86,10 @@ export const fetchGlobalProps = async () => {
|
||||
}
|
||||
|
||||
const steemPerMVests =
|
||||
(parseToken(
|
||||
get(globalDynamic, 'total_vesting_fund_steem', globalDynamic.total_vesting_fund_hive),
|
||||
) /
|
||||
(parseToken(get(globalDynamic, 'total_vesting_fund_hive')) /
|
||||
parseToken(get(globalDynamic, 'total_vesting_shares'))) *
|
||||
1e6;
|
||||
const sbdPrintRate = get(globalDynamic, 'sbd_print_rate', globalDynamic.hbd_print_rate);
|
||||
const sbdPrintRate = get(globalDynamic, 'hbd_print_rate');
|
||||
const base = parseAsset(get(feedHistory, 'current_median_history.base')).amount;
|
||||
const quote = parseAsset(get(feedHistory, 'current_median_history.quote')).amount;
|
||||
const fundRecentClaims = get(rewardFund, 'recent_claims');
|
||||
@ -216,17 +214,17 @@ export const getUser = async (user, loggedIn = true) => {
|
||||
_account.steem_power = await vestToSteem(
|
||||
_account.vesting_shares,
|
||||
globalProperties.total_vesting_shares,
|
||||
globalProperties.total_vesting_fund_steem || globalProperties.total_vesting_fund_hive,
|
||||
globalProperties.total_vesting_fund_hive,
|
||||
);
|
||||
_account.received_steem_power = await vestToSteem(
|
||||
get(_account, 'received_vesting_shares'),
|
||||
get(globalProperties, 'total_vesting_shares'),
|
||||
get(globalProperties, 'total_vesting_fund_steem', globalProperties.total_vesting_fund_hive),
|
||||
get(globalProperties, 'total_vesting_fund_hive'),
|
||||
);
|
||||
_account.delegated_steem_power = await vestToSteem(
|
||||
get(_account, 'delegated_vesting_shares'),
|
||||
get(globalProperties, 'total_vesting_shares'),
|
||||
get(globalProperties, 'total_vesting_fund_steem', globalProperties.total_vesting_fund_hive),
|
||||
get(globalProperties, 'total_vesting_fund_hive'),
|
||||
);
|
||||
|
||||
if (has(_account, 'posting_json_metadata')) {
|
||||
@ -316,7 +314,8 @@ export const getCommunities = async (
|
||||
resolve({});
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
console.log(error);
|
||||
resolve({});
|
||||
}
|
||||
});
|
||||
|
||||
@ -459,7 +458,7 @@ export const getRankedPosts = async (query, currentUserName, filterNsfw) => {
|
||||
let posts = await client.call('bridge', 'get_ranked_posts', query);
|
||||
|
||||
if (posts) {
|
||||
posts = parsePosts(posts, currentUserName, true);
|
||||
posts = parsePosts(posts, currentUserName);
|
||||
|
||||
if (filterNsfw !== '0') {
|
||||
const updatedPosts = filterNsfwPost(posts, filterNsfw);
|
||||
@ -477,7 +476,7 @@ export const getAccountPosts = async (query, currentUserName, filterNsfw) => {
|
||||
let posts = await client.call('bridge', 'get_account_posts', query);
|
||||
|
||||
if (posts) {
|
||||
posts = parsePosts(posts, currentUserName, true);
|
||||
posts = parsePosts(posts, currentUserName);
|
||||
|
||||
if (filterNsfw !== '0') {
|
||||
const updatedPosts = filterNsfwPost(posts, filterNsfw);
|
||||
@ -1140,9 +1139,9 @@ export const lookupAccounts = async (username) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const getTrendingTags = async (tag) => {
|
||||
export const getTrendingTags = async (tag, number = 20) => {
|
||||
try {
|
||||
const tags = await client.database.call('get_trending_tags', [tag, 20]);
|
||||
const tags = await client.database.call('get_trending_tags', [tag, number]);
|
||||
return tags;
|
||||
} catch (error) {
|
||||
return [];
|
||||
|
@ -61,19 +61,26 @@ export const fetchSubscribedCommunitiesFail = (payload) => ({
|
||||
});
|
||||
|
||||
// Subscribe Community
|
||||
export const subscribeCommunity = (currentAccount, pin, data, successToastText, failToastText) => {
|
||||
export const subscribeCommunity = (
|
||||
currentAccount,
|
||||
pin,
|
||||
data,
|
||||
successToastText,
|
||||
failToastText,
|
||||
screen,
|
||||
) => {
|
||||
return (dispatch) => {
|
||||
dispatch({ type: SUBSCRIBE_COMMUNITY, payload: data });
|
||||
dispatch({ type: SUBSCRIBE_COMMUNITY, payload: { ...data, screen } });
|
||||
subscribeCommunityReq(currentAccount, pin, data)
|
||||
.then((res) => dispatch(subscribeCommunitySuccess(data, successToastText)))
|
||||
.catch((err) => dispatch(subscribeCommunityFail(err, data, failToastText)));
|
||||
.then((res) => dispatch(subscribeCommunitySuccess(data, successToastText, screen)))
|
||||
.catch((err) => dispatch(subscribeCommunityFail(err, data, failToastText, screen)));
|
||||
};
|
||||
};
|
||||
|
||||
export const subscribeCommunitySuccess = (data, successToastText) => {
|
||||
export const subscribeCommunitySuccess = (data, successToastText, screen) => {
|
||||
return (dispatch) => [
|
||||
dispatch({
|
||||
payload: data,
|
||||
payload: { ...data, screen },
|
||||
type: SUBSCRIBE_COMMUNITY_SUCCESS,
|
||||
}),
|
||||
dispatch({
|
||||
@ -83,10 +90,10 @@ export const subscribeCommunitySuccess = (data, successToastText) => {
|
||||
];
|
||||
};
|
||||
|
||||
export const subscribeCommunityFail = (error, data, failToastText) => {
|
||||
export const subscribeCommunityFail = (error, data, failToastText, screen) => {
|
||||
return (dispatch) => [
|
||||
dispatch({
|
||||
payload: data,
|
||||
payload: { ...data, screen },
|
||||
type: SUBSCRIBE_COMMUNITY_FAIL,
|
||||
}),
|
||||
dispatch({
|
||||
@ -97,19 +104,26 @@ export const subscribeCommunityFail = (error, data, failToastText) => {
|
||||
};
|
||||
|
||||
// Leave Community
|
||||
export const leaveCommunity = (currentAccount, pin, data, successToastText, failToastText) => {
|
||||
export const leaveCommunity = (
|
||||
currentAccount,
|
||||
pin,
|
||||
data,
|
||||
successToastText,
|
||||
failToastText,
|
||||
screen,
|
||||
) => {
|
||||
return (dispatch) => {
|
||||
dispatch({ type: LEAVE_COMMUNITY, payload: data });
|
||||
dispatch({ type: LEAVE_COMMUNITY, payload: { ...data, screen } });
|
||||
subscribeCommunityReq(currentAccount, pin, data)
|
||||
.then((res) => dispatch(leaveCommunitySuccess(data, successToastText)))
|
||||
.catch((err) => dispatch(leaveCommunityFail(err, data, failToastText)));
|
||||
.then((res) => dispatch(leaveCommunitySuccess(data, successToastText, screen)))
|
||||
.catch((err) => dispatch(leaveCommunityFail(err, data, failToastText, screen)));
|
||||
};
|
||||
};
|
||||
|
||||
export const leaveCommunitySuccess = (data, successToastText) => {
|
||||
export const leaveCommunitySuccess = (data, successToastText, screen) => {
|
||||
return (dispatch) => [
|
||||
dispatch({
|
||||
payload: data,
|
||||
payload: { ...data, screen },
|
||||
type: LEAVE_COMMUNITY_SUCCESS,
|
||||
}),
|
||||
dispatch({
|
||||
@ -119,10 +133,10 @@ export const leaveCommunitySuccess = (data, successToastText) => {
|
||||
];
|
||||
};
|
||||
|
||||
export const leaveCommunityFail = (error, data, failToastText) => {
|
||||
export const leaveCommunityFail = (error, data, failToastText, screen) => {
|
||||
return (dispatch) => [
|
||||
dispatch({
|
||||
payload: data,
|
||||
payload: { ...data, screen },
|
||||
type: LEAVE_COMMUNITY_FAIL,
|
||||
}),
|
||||
dispatch({
|
||||
|
@ -31,6 +31,27 @@ const initialState = {
|
||||
// error: false,
|
||||
//}
|
||||
},
|
||||
subscribingCommunitiesInCommunitiesScreenDiscoverTab: {
|
||||
//['name']: {
|
||||
// isSubscribed: false,
|
||||
// loading: false,
|
||||
// error: false,
|
||||
//}
|
||||
},
|
||||
subscribingCommunitiesInCommunitiesScreenJoinedTab: {
|
||||
//['name']: {
|
||||
// isSubscribed: false,
|
||||
// loading: false,
|
||||
// error: false,
|
||||
//}
|
||||
},
|
||||
subscribingCommunitiesInSearchResultsScreen: {
|
||||
//['name']: {
|
||||
// isSubscribed: false,
|
||||
// loading: false,
|
||||
// error: false,
|
||||
//}
|
||||
},
|
||||
};
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
@ -90,6 +111,32 @@ export default function (state = initialState, action) {
|
||||
},
|
||||
};
|
||||
case SUBSCRIBE_COMMUNITY:
|
||||
switch (action.payload.screen) {
|
||||
case 'communitiesScreenDiscoverTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenDiscoverTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenDiscoverTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: false,
|
||||
loading: true,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'communitiesScreenJoinedTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenJoinedTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenJoinedTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: false,
|
||||
loading: true,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'feedScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInFeedScreen: {
|
||||
@ -101,7 +148,48 @@ export default function (state = initialState, action) {
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'searchResultsScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInSearchResultsScreen: {
|
||||
...state.subscribingCommunitiesInSearchResultsScreen,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: false,
|
||||
loading: true,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
case SUBSCRIBE_COMMUNITY_SUCCESS:
|
||||
switch (action.payload.screen) {
|
||||
case 'communitiesScreenDiscoverTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenDiscoverTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenDiscoverTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: true,
|
||||
loading: false,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'communitiesScreenJoinedTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenJoinedTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenJoinedTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: true,
|
||||
loading: false,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'feedScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInFeedScreen: {
|
||||
@ -113,7 +201,48 @@ export default function (state = initialState, action) {
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'searchResultsScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInSearchResultsScreen: {
|
||||
...state.subscribingCommunitiesInSearchResultsScreen,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: true,
|
||||
loading: false,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
case SUBSCRIBE_COMMUNITY_FAIL:
|
||||
switch (action.payload.screen) {
|
||||
case 'communitiesScreenDiscoverTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenDiscoverTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenDiscoverTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: false,
|
||||
loading: false,
|
||||
error: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'communitiesScreenJoinedTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenJoinedTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenJoinedTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: false,
|
||||
loading: false,
|
||||
error: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'feedScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInFeedScreen: {
|
||||
@ -125,7 +254,48 @@ export default function (state = initialState, action) {
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'searchResultsScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInSearchResultsScreen: {
|
||||
...state.subscribingCommunitiesInSearchResultsScreen,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: false,
|
||||
loading: false,
|
||||
error: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
case LEAVE_COMMUNITY:
|
||||
switch (action.payload.screen) {
|
||||
case 'communitiesScreenDiscoverTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenDiscoverTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenDiscoverTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: true,
|
||||
loading: true,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'communitiesScreenJoinedTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenJoinedTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenJoinedTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: true,
|
||||
loading: true,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'feedScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInFeedScreen: {
|
||||
@ -137,7 +307,48 @@ export default function (state = initialState, action) {
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'searchResultsScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInSearchResultsScreen: {
|
||||
...state.subscribingCommunitiesInSearchResultsScreen,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: true,
|
||||
loading: true,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
case LEAVE_COMMUNITY_SUCCESS:
|
||||
switch (action.payload.screen) {
|
||||
case 'communitiesScreenDiscoverTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenDiscoverTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenDiscoverTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: false,
|
||||
loading: false,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'communitiesScreenJoinedTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenJoinedTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenJoinedTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: false,
|
||||
loading: false,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'feedScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInFeedScreen: {
|
||||
@ -149,7 +360,48 @@ export default function (state = initialState, action) {
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'searchResultsScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInSearchResultsScreen: {
|
||||
...state.subscribingCommunitiesInSearchResultsScreen,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: false,
|
||||
loading: false,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
case LEAVE_COMMUNITY_FAIL:
|
||||
switch (action.payload.screen) {
|
||||
case 'communitiesScreenDiscoverTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenDiscoverTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenDiscoverTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: true,
|
||||
loading: false,
|
||||
error: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'communitiesScreenJoinedTab':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInCommunitiesScreenJoinedTab: {
|
||||
...state.subscribingCommunitiesInCommunitiesScreenJoinedTab,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: true,
|
||||
loading: false,
|
||||
error: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'feedScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInFeedScreen: {
|
||||
@ -161,6 +413,21 @@ export default function (state = initialState, action) {
|
||||
},
|
||||
},
|
||||
};
|
||||
case 'searchResultsScreen':
|
||||
return {
|
||||
...state,
|
||||
subscribingCommunitiesInSearchResultsScreen: {
|
||||
...state.subscribingCommunitiesInSearchResultsScreen,
|
||||
[action.payload.communityId]: {
|
||||
isSubscribed: true,
|
||||
loading: false,
|
||||
error: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
153
src/screens/communities/container/communitiesContainer.js
Normal file
153
src/screens/communities/container/communitiesContainer.js
Normal file
@ -0,0 +1,153 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { shuffle } from 'lodash';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
import ROUTES from '../../../constants/routeNames';
|
||||
|
||||
import { getCommunities, getSubscriptions } from '../../../providers/hive/dhive';
|
||||
|
||||
import { toastNotification } from '../../../redux/actions/uiAction';
|
||||
import { subscribeCommunity, leaveCommunity } from '../../../redux/actions/communitiesAction';
|
||||
|
||||
const CommunitiesContainer = ({ children, navigation }) => {
|
||||
const dispatch = useDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const [discovers, setDiscovers] = useState([]);
|
||||
const [subscriptions, setSubscriptions] = useState([]);
|
||||
|
||||
const currentAccount = useSelector((state) => state.account.currentAccount);
|
||||
const pinCode = useSelector((state) => state.application.pin);
|
||||
const subscribingCommunitiesInDiscoverTab = useSelector(
|
||||
(state) => state.communities.subscribingCommunitiesInCommunitiesScreenDiscoverTab,
|
||||
);
|
||||
const subscribingCommunitiesInJoinedTab = useSelector(
|
||||
(state) => state.communities.subscribingCommunitiesInCommunitiesScreenJoinedTab,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
getSubscriptions(currentAccount.username).then((subs) => {
|
||||
subs.forEach((item) => item.push(true));
|
||||
getCommunities('', 50, '', 'rank').then((communities) => {
|
||||
communities.forEach((community) =>
|
||||
Object.assign(community, {
|
||||
isSubscribed: subs.some(
|
||||
(subscribedCommunity) => subscribedCommunity[0] === community.name,
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
setSubscriptions(subs);
|
||||
setDiscovers(shuffle(communities));
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const discoversData = [...discovers];
|
||||
|
||||
Object.keys(subscribingCommunitiesInDiscoverTab).map((communityId) => {
|
||||
if (!subscribingCommunitiesInDiscoverTab[communityId].loading) {
|
||||
if (!subscribingCommunitiesInDiscoverTab[communityId].error) {
|
||||
if (subscribingCommunitiesInDiscoverTab[communityId].isSubscribed) {
|
||||
discoversData.forEach((item) => {
|
||||
if (item.name === communityId) {
|
||||
item.isSubscribed = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
discoversData.forEach((item) => {
|
||||
if (item.name === communityId) {
|
||||
item.isSubscribed = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setDiscovers(discoversData);
|
||||
}, [subscribingCommunitiesInDiscoverTab]);
|
||||
|
||||
useEffect(() => {
|
||||
const subscribedsData = [...subscriptions];
|
||||
|
||||
Object.keys(subscribingCommunitiesInJoinedTab).map((communityId) => {
|
||||
if (!subscribingCommunitiesInJoinedTab[communityId].loading) {
|
||||
if (!subscribingCommunitiesInJoinedTab[communityId].error) {
|
||||
if (subscribingCommunitiesInJoinedTab[communityId].isSubscribed) {
|
||||
subscribedsData.forEach((item) => {
|
||||
if (item[0] === communityId) {
|
||||
item[4] = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
subscribedsData.forEach((item) => {
|
||||
if (item[0] === communityId) {
|
||||
item[4] = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setSubscriptions(subscribedsData);
|
||||
}, [subscribingCommunitiesInJoinedTab]);
|
||||
|
||||
// Component Functions
|
||||
const _handleOnPress = (name) => {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.COMMUNITY,
|
||||
params: {
|
||||
tag: name,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const _handleSubscribeButtonPress = (data, screen) => {
|
||||
let subscribeAction;
|
||||
let successToastText = '';
|
||||
let failToastText = '';
|
||||
|
||||
if (!data.isSubscribed) {
|
||||
subscribeAction = subscribeCommunity;
|
||||
|
||||
successToastText = intl.formatMessage({
|
||||
id: 'alert.success_subscribe',
|
||||
});
|
||||
failToastText = intl.formatMessage({
|
||||
id: 'alert.fail_subscribe',
|
||||
});
|
||||
} else {
|
||||
subscribeAction = leaveCommunity;
|
||||
|
||||
successToastText = intl.formatMessage({
|
||||
id: 'alert.success_leave',
|
||||
});
|
||||
failToastText = intl.formatMessage({
|
||||
id: 'alert.fail_leave',
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(
|
||||
subscribeAction(currentAccount, pinCode, data, successToastText, failToastText, screen),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
children &&
|
||||
children({
|
||||
subscriptions,
|
||||
discovers,
|
||||
subscribingCommunitiesInDiscoverTab,
|
||||
subscribingCommunitiesInJoinedTab,
|
||||
handleOnPress: _handleOnPress,
|
||||
handleSubscribeButtonPress: _handleSubscribeButtonPress,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
export default withNavigation(CommunitiesContainer);
|
3
src/screens/communities/index.js
Normal file
3
src/screens/communities/index.js
Normal file
@ -0,0 +1,3 @@
|
||||
import Communities from './view/communitiesScreen';
|
||||
|
||||
export default Communities;
|
106
src/screens/communities/view/communitiesScreen.js
Normal file
106
src/screens/communities/view/communitiesScreen.js
Normal file
@ -0,0 +1,106 @@
|
||||
import React from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { FlatList, View, Text, TouchableOpacity } from 'react-native';
|
||||
import get from 'lodash/get';
|
||||
import { SafeAreaView } from 'react-navigation';
|
||||
import ScrollableTabView from 'react-native-scrollable-tab-view';
|
||||
|
||||
// Components
|
||||
import {
|
||||
FilterBar,
|
||||
UserAvatar,
|
||||
TabBar,
|
||||
BasicHeader,
|
||||
CommunitiesList,
|
||||
SubscribedCommunitiesList,
|
||||
} from '../../../components';
|
||||
import { CommunitiesPlaceHolder } from '../../../components/basicUIElements';
|
||||
|
||||
import CommunitiesContainer from '../container/communitiesContainer';
|
||||
import DEFAULT_IMAGE from '../../../assets/no_image.png';
|
||||
import Tag from '../../../components/basicUIElements/view/tag/tagView';
|
||||
|
||||
import styles from './communitiesScreenStyles';
|
||||
import globalStyles from '../../../globalStyles';
|
||||
|
||||
const CommunitiesScreen = ({ navigation, searchValue }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const _renderEmptyContent = () => {
|
||||
return (
|
||||
<>
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const _renderTabbar = () => (
|
||||
<TabBar
|
||||
style={styles.tabbar}
|
||||
tabUnderlineDefaultWidth={80}
|
||||
tabUnderlineScaleX={2}
|
||||
tabBarPosition="overlayTop"
|
||||
textStyle={styles.tabBarText}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<CommunitiesContainer>
|
||||
{({
|
||||
subscriptions,
|
||||
discovers,
|
||||
handleOnPress,
|
||||
handleSubscribeButtonPress,
|
||||
subscribingCommunitiesInDiscoverTab,
|
||||
subscribingCommunitiesInJoinedTab,
|
||||
}) => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<SafeAreaView forceInset={{ bottom: 'never' }} style={{ flex: 1 }}>
|
||||
<BasicHeader
|
||||
title={intl.formatMessage({
|
||||
id: 'side_menu.communities',
|
||||
})}
|
||||
/>
|
||||
<ScrollableTabView
|
||||
style={globalStyles.tabView}
|
||||
renderTabBar={_renderTabbar}
|
||||
prerenderingSiblingsNumber={Infinity}
|
||||
>
|
||||
<View
|
||||
tabLabel={intl.formatMessage({ id: 'communities.joined' })}
|
||||
style={styles.tabbarItem}
|
||||
>
|
||||
<SubscribedCommunitiesList
|
||||
data={subscriptions}
|
||||
subscribingCommunities={subscribingCommunitiesInJoinedTab}
|
||||
handleSubscribeButtonPress={handleSubscribeButtonPress}
|
||||
handleOnPress={handleOnPress}
|
||||
/>
|
||||
</View>
|
||||
<View
|
||||
tabLabel={intl.formatMessage({ id: 'communities.discover' })}
|
||||
style={styles.tabbarItem}
|
||||
>
|
||||
<CommunitiesList
|
||||
data={discovers}
|
||||
subscribingCommunities={subscribingCommunitiesInDiscoverTab}
|
||||
handleOnPress={handleOnPress}
|
||||
handleSubscribeButtonPress={handleSubscribeButtonPress}
|
||||
isLoggedIn={true}
|
||||
noResult={discovers.length === 0}
|
||||
screen="communitiesScreenDiscoverTab"
|
||||
/>
|
||||
</View>
|
||||
</ScrollableTabView>
|
||||
</SafeAreaView>
|
||||
</View>
|
||||
);
|
||||
}}
|
||||
</CommunitiesContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommunitiesScreen;
|
51
src/screens/communities/view/communitiesScreenStyles.js
Normal file
51
src/screens/communities/view/communitiesScreenStyles.js
Normal file
@ -0,0 +1,51 @@
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
},
|
||||
itemWrapper: {
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 16,
|
||||
paddingBottom: 8,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
itemWrapperGray: {
|
||||
backgroundColor: '$primaryLightBackground',
|
||||
},
|
||||
username: {
|
||||
marginLeft: 10,
|
||||
color: '$primaryBlack',
|
||||
},
|
||||
communityWrapper: {
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
},
|
||||
subscribeButton: {
|
||||
maxWidth: 75,
|
||||
borderWidth: 1,
|
||||
borderColor: '$primaryBlue',
|
||||
},
|
||||
subscribeButtonText: {
|
||||
textAlign: 'center',
|
||||
color: '$primaryBlue',
|
||||
},
|
||||
community: {
|
||||
justifyContent: 'center',
|
||||
marginLeft: 15,
|
||||
color: '$primaryBlack',
|
||||
},
|
||||
tabbarItem: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
@ -13,7 +13,7 @@ import styles from './communityStyles';
|
||||
|
||||
import { GLOBAL_POST_FILTERS, GLOBAL_POST_FILTERS_VALUE } from '../../../constants/options/filters';
|
||||
|
||||
const TagResultScreen = ({ navigation }) => {
|
||||
const CommunityScreen = ({ navigation }) => {
|
||||
const tag = navigation.getParam('tag', '');
|
||||
const filter = navigation.getParam('filter', '');
|
||||
|
||||
@ -114,4 +114,4 @@ const TagResultScreen = ({ navigation }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default TagResultScreen;
|
||||
export default CommunityScreen;
|
||||
|
@ -47,6 +47,7 @@ const DraftsScreen = ({
|
||||
const tags = item.tags ? item.tags.split(/[ ,]+/) : [];
|
||||
const tag = tags[0] || '';
|
||||
const image = catchDraftImage(item.body);
|
||||
const thumbnail = catchDraftImage(item.body, 'match', true);
|
||||
const summary = postBodySummary({ item, last_update: item.created }, 100);
|
||||
const isSchedules = type === 'schedules';
|
||||
|
||||
@ -57,7 +58,8 @@ const DraftsScreen = ({
|
||||
title={item.title}
|
||||
summary={summary}
|
||||
isFormatedDate={isSchedules}
|
||||
image={image ? { uri: catchDraftImage(item.body) } : null}
|
||||
image={image ? { uri: image } : null}
|
||||
thumbnail={thumbnail ? { uri: thumbnail } : null}
|
||||
username={currentAccount.name}
|
||||
reputation={currentAccount.reputation}
|
||||
handleOnPressItem={() => (isSchedules ? setSelectedId(item._id) : editDraft(item._id))}
|
||||
|
@ -24,6 +24,7 @@ import AccountBoost from './accountBoost/screen/accountBoostScreen';
|
||||
import Register from './register/registerScreen';
|
||||
import TagResult from './tagResult';
|
||||
import { Community } from './community';
|
||||
import Communities from './communities';
|
||||
|
||||
export {
|
||||
Bookmarks,
|
||||
@ -52,4 +53,5 @@ export {
|
||||
Wallet,
|
||||
TagResult,
|
||||
Community,
|
||||
Communities,
|
||||
};
|
||||
|
@ -1,111 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { connect } from 'react-redux';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
|
||||
import ROUTES from '../../../constants/routeNames';
|
||||
|
||||
import {
|
||||
subscribeCommunity,
|
||||
getCommunities,
|
||||
getSubscriptions,
|
||||
} from '../../../providers/hive/dhive';
|
||||
|
||||
const CommunitiesContainer = ({
|
||||
children,
|
||||
navigation,
|
||||
searchValue,
|
||||
currentAccount,
|
||||
pinCode,
|
||||
isLoggedIn,
|
||||
}) => {
|
||||
const [data, setData] = useState();
|
||||
const [filterIndex, setFilterIndex] = useState(1);
|
||||
const [query, setQuery] = useState('');
|
||||
const [sort, setSort] = useState('rank');
|
||||
const [allSubscriptions, setAllSubscriptions] = useState([]);
|
||||
const [noResult, setNoResult] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let isCancelled = false;
|
||||
setData([]);
|
||||
if (sort === 'my') {
|
||||
setNoResult(true);
|
||||
} else {
|
||||
getCommunities('', 100, query, sort).then((res) => {
|
||||
if (!isCancelled) {
|
||||
if (!isEmpty(res)) {
|
||||
setData(res);
|
||||
setNoResult(false);
|
||||
} else {
|
||||
setNoResult(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
};
|
||||
}, [query, sort]);
|
||||
|
||||
useEffect(() => {
|
||||
setData([]);
|
||||
setQuery(searchValue);
|
||||
setNoResult(false);
|
||||
}, [searchValue]);
|
||||
|
||||
useEffect(() => {
|
||||
let isCancelled = false;
|
||||
if (data && !isCancelled) {
|
||||
getSubscriptions(currentAccount.username).then((result) => {
|
||||
if (result) {
|
||||
setAllSubscriptions(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
};
|
||||
}, [data]);
|
||||
|
||||
// Component Functions
|
||||
const _handleOnVotersDropdownSelect = (index, value) => {
|
||||
setFilterIndex(index);
|
||||
setSort(value);
|
||||
};
|
||||
|
||||
const _handleOnPress = (name) => {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.COMMUNITY,
|
||||
params: {
|
||||
tag: name,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const _handleSubscribeButtonPress = (_data) => {
|
||||
return subscribeCommunity(currentAccount, pinCode, _data);
|
||||
};
|
||||
|
||||
return (
|
||||
children &&
|
||||
children({
|
||||
data,
|
||||
filterIndex,
|
||||
allSubscriptions,
|
||||
handleOnVotersDropdownSelect: _handleOnVotersDropdownSelect,
|
||||
handleOnPress: _handleOnPress,
|
||||
handleSubscribeButtonPress: _handleSubscribeButtonPress,
|
||||
isLoggedIn,
|
||||
noResult,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
currentAccount: state.account.currentAccount,
|
||||
pinCode: state.application.pin,
|
||||
isLoggedIn: state.application.isLoggedIn,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withNavigation(CommunitiesContainer));
|
@ -1,84 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import ROUTES from '../../../constants/routeNames';
|
||||
|
||||
import { lookupAccounts, getTrendingTags } from '../../../providers/hive/dhive';
|
||||
import { getLeaderboard } from '../../../providers/ecency/ecency';
|
||||
|
||||
const OtherResultContainer = (props) => {
|
||||
const [users, setUsers] = useState([]);
|
||||
const [tags, setTags] = useState([]);
|
||||
const [filterIndex, setFilterIndex] = useState(0);
|
||||
|
||||
const { children, navigation, searchValue, username } = props;
|
||||
|
||||
useEffect(() => {
|
||||
setUsers([]);
|
||||
setTags([]);
|
||||
|
||||
if (searchValue) {
|
||||
lookupAccounts(searchValue.replace(/\s+/g, '')).then((res) => {
|
||||
setUsers(res);
|
||||
});
|
||||
getTrendingTags(searchValue.replace(/\s+/g, '')).then((res) => {
|
||||
setTags(res);
|
||||
});
|
||||
} else {
|
||||
getLeaderboard().then((result) => {
|
||||
const sos = result.map((item) => item._id);
|
||||
setUsers(sos);
|
||||
});
|
||||
}
|
||||
}, [searchValue]);
|
||||
|
||||
// Component Functions
|
||||
|
||||
const _handleOnPress = (item) => {
|
||||
switch (filterIndex) {
|
||||
case 0:
|
||||
navigation.navigate({
|
||||
routeName: item === username ? ROUTES.TABBAR.PROFILE : ROUTES.SCREENS.PROFILE,
|
||||
params: {
|
||||
username: item,
|
||||
},
|
||||
key: item.text,
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.TAG_RESULT,
|
||||
params: {
|
||||
tag: get(item, 'name', ''),
|
||||
},
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const _handleFilterChanged = (index, value) => {
|
||||
setFilterIndex(index);
|
||||
};
|
||||
|
||||
return (
|
||||
children &&
|
||||
children({
|
||||
users,
|
||||
tags,
|
||||
filterIndex,
|
||||
handleOnPress: _handleOnPress,
|
||||
handleFilterChanged: _handleFilterChanged,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
username: state.account.currentAccount.name,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withNavigation(OtherResultContainer));
|
@ -1,91 +0,0 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import ROUTES from '../../../constants/routeNames';
|
||||
|
||||
import { search, getPromotePosts } from '../../../providers/ecency/ecency';
|
||||
import { getPost } from '../../../providers/hive/dhive';
|
||||
|
||||
const PostResultContainer = ({ children, navigation, searchValue, currentAccountUsername }) => {
|
||||
const [data, setData] = useState([]);
|
||||
const [filterIndex, setFilterIndex] = useState(0);
|
||||
const [sort, setSort] = useState('relevance');
|
||||
const [scrollId, setScrollId] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
setData([]);
|
||||
|
||||
if (searchValue) {
|
||||
search({ q: searchValue, sort }).then((res) => {
|
||||
setScrollId(res.scroll_id);
|
||||
setData(res.results);
|
||||
});
|
||||
} else {
|
||||
getPromotePosts()
|
||||
.then((result) => {
|
||||
return Promise.all(
|
||||
result.map((item) =>
|
||||
getPost(
|
||||
get(item, 'author'),
|
||||
get(item, 'permlink'),
|
||||
currentAccountUsername,
|
||||
true,
|
||||
).then((post) => {
|
||||
post.author_rep = post.author_reputation;
|
||||
post.body = (post.summary && post.summary.substring(0, 130)) || '';
|
||||
return post;
|
||||
}),
|
||||
),
|
||||
);
|
||||
})
|
||||
.then((result) => {
|
||||
setData(result);
|
||||
});
|
||||
}
|
||||
}, [searchValue, sort]);
|
||||
|
||||
// Component Functions
|
||||
|
||||
const _handleOnPress = (item) => {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.POST,
|
||||
params: {
|
||||
author: get(item, 'author'),
|
||||
permlink: get(item, 'permlink'),
|
||||
},
|
||||
key: get(item, 'permlink'),
|
||||
});
|
||||
};
|
||||
|
||||
const _handleFilterChanged = (index, value) => {
|
||||
setFilterIndex(index);
|
||||
setSort(value);
|
||||
};
|
||||
|
||||
const _loadMore = (index, value) => {
|
||||
if (scrollId) {
|
||||
search({ q: searchValue, sort, scroll_id: scrollId }).then((res) => {
|
||||
setData([...data, ...res.results]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
children &&
|
||||
children({
|
||||
data,
|
||||
filterIndex,
|
||||
handleOnPress: _handleOnPress,
|
||||
handleFilterChanged: _handleFilterChanged,
|
||||
loadMore: _loadMore,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
currentAccountUsername: state.account.currentAccount.username,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withNavigation(PostResultContainer));
|
@ -1,108 +0,0 @@
|
||||
import React from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { FlatList, View, Text, TouchableOpacity } from 'react-native';
|
||||
import get from 'lodash/get';
|
||||
|
||||
// Components
|
||||
import { FilterBar, UserAvatar } from '../../../components';
|
||||
import CommunitiesList from './communitiesList';
|
||||
import { CommunitiesPlaceHolder } from '../../../components/basicUIElements';
|
||||
|
||||
import CommunitiesContainer from '../container/communitiesContainer';
|
||||
import styles from './otherResultsStyles';
|
||||
import DEFAULT_IMAGE from '../../../assets/no_image.png';
|
||||
import Tag from '../../../components/basicUIElements/view/tag/tagView';
|
||||
|
||||
const filterOptions = ['my', 'rank', 'subs', 'new'];
|
||||
|
||||
const CommunitiesScreen = ({ navigation, searchValue }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const activeVotes = get(navigation, 'state.params.activeVotes');
|
||||
|
||||
const _renderEmptyContent = () => {
|
||||
return (
|
||||
<>
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<CommunitiesContainer data={activeVotes} searchValue={searchValue}>
|
||||
{({
|
||||
data,
|
||||
filterIndex,
|
||||
allSubscriptions,
|
||||
handleOnVotersDropdownSelect,
|
||||
handleOnPress,
|
||||
handleSubscribeButtonPress,
|
||||
isLoggedIn,
|
||||
noResult,
|
||||
}) => (
|
||||
<>
|
||||
<FilterBar
|
||||
dropdownIconName="arrow-drop-down"
|
||||
options={filterOptions.map((item) =>
|
||||
intl.formatMessage({
|
||||
id: `search_result.communities_filter.${item}`,
|
||||
}),
|
||||
)}
|
||||
defaultText={intl.formatMessage({
|
||||
id: `search_result.communities_filter.${filterOptions[filterIndex]}`,
|
||||
})}
|
||||
selectedOptionIndex={filterIndex}
|
||||
onDropdownSelect={(index) => handleOnVotersDropdownSelect(index, filterOptions[index])}
|
||||
/>
|
||||
{filterIndex !== 0 && (
|
||||
<CommunitiesList
|
||||
votes={data}
|
||||
allSubscriptions={allSubscriptions}
|
||||
handleOnPress={handleOnPress}
|
||||
handleSubscribeButtonPress={handleSubscribeButtonPress}
|
||||
isLoggedIn={isLoggedIn}
|
||||
noResult={noResult}
|
||||
/>
|
||||
)}
|
||||
{filterIndex === 0 && allSubscriptions && allSubscriptions.length > 0 && (
|
||||
<FlatList
|
||||
data={allSubscriptions}
|
||||
//keyExtractor={(item, ind) => `${item}-${ind}`}
|
||||
renderItem={({ item, index }) => (
|
||||
<View style={[styles.communityWrapper, index % 2 !== 0 && styles.itemWrapperGray]}>
|
||||
<View style={{ flex: 3, flexDirection: 'row', alignItems: 'center' }}>
|
||||
<TouchableOpacity onPress={() => handleOnPress(item[0])}>
|
||||
<UserAvatar username={item[0]} defaultSource={DEFAULT_IMAGE} noAction />
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity onPress={() => handleOnPress(item[0])}>
|
||||
<Text style={styles.community}>{item[1]}</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Tag
|
||||
style={styles.subscribeButton}
|
||||
textStyle={styles.subscribeButtonText}
|
||||
value={intl.formatMessage({
|
||||
id: 'search_result.communities.unsubscribe',
|
||||
})}
|
||||
isPin={false}
|
||||
isFilter
|
||||
onPress={() =>
|
||||
handleSubscribeButtonPress({ isSubscribed: true, communityId: item[0] })
|
||||
}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
ListEmptyComponent={_renderEmptyContent}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</CommunitiesContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommunitiesScreen;
|
@ -1,107 +0,0 @@
|
||||
import React from 'react';
|
||||
import { SafeAreaView, FlatList, View, Text, TouchableOpacity } from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
// Components
|
||||
import { FilterBar, UserAvatar } from '../../../components';
|
||||
import { CommunitiesPlaceHolder } from '../../../components/basicUIElements';
|
||||
import OtherResultContainer from '../container/otherResultContainer';
|
||||
|
||||
import styles from './otherResultsStyles';
|
||||
|
||||
import DEFAULT_IMAGE from '../../../assets/no_image.png';
|
||||
|
||||
const filterOptions = ['user', 'tag'];
|
||||
|
||||
const OtherResult = ({ navigation, searchValue }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const _renderUserItem = (item, index) => (
|
||||
<View style={[styles.itemWrapper, index % 2 !== 0 && styles.itemWrapperGray]}>
|
||||
<UserAvatar username={item} defaultSource={DEFAULT_IMAGE} noAction />
|
||||
<Text style={styles.username}>{item}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const _renderTagItem = (item, index) => (
|
||||
<View style={[styles.itemWrapper, index % 2 !== 0 && styles.itemWrapperGray]}>
|
||||
<Text style={styles.username}>{`#${item.name}`}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const _renderEmptyContent = () => {
|
||||
return (
|
||||
<>
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
<CommunitiesPlaceHolder />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const _renderList = (users, tags, filterIndex, handleOnPress) => {
|
||||
switch (filterIndex) {
|
||||
case 0:
|
||||
if (users && users.length > 0) {
|
||||
return (
|
||||
<FlatList
|
||||
data={users}
|
||||
keyExtractor={(item, ind) => `${item}-${ind}`}
|
||||
renderItem={({ item, index }) => (
|
||||
<TouchableOpacity onPress={() => handleOnPress(item)}>
|
||||
{_renderUserItem(item, index)}
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
ListEmptyComponent={_renderEmptyContent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
case 1:
|
||||
if (tags && tags.length > 0) {
|
||||
return (
|
||||
<FlatList
|
||||
data={tags}
|
||||
keyExtractor={(item) => `${item.name}-${item.comments}`}
|
||||
renderItem={({ item, index }) => (
|
||||
<TouchableOpacity onPress={() => handleOnPress(item)}>
|
||||
{_renderTagItem(item, index)}
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
ListEmptyComponent={_renderEmptyContent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<OtherResultContainer searchValue={searchValue}>
|
||||
{({ users, tags, filterIndex, handleFilterChanged, handleOnPress, loadMore }) => (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<FilterBar
|
||||
dropdownIconName="arrow-drop-down"
|
||||
options={filterOptions.map((item) =>
|
||||
intl.formatMessage({
|
||||
id: `search_result.other_result_filter.${item}`,
|
||||
}),
|
||||
)}
|
||||
defaultText={intl.formatMessage({
|
||||
id: `search_result.other_result_filter.${filterOptions[filterIndex]}`,
|
||||
})}
|
||||
selectedOptionIndex={filterIndex}
|
||||
onDropdownSelect={(index) => handleFilterChanged(index, filterOptions[index])}
|
||||
/>
|
||||
{_renderList(users, tags, filterIndex, handleOnPress)}
|
||||
</SafeAreaView>
|
||||
)}
|
||||
</OtherResultContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default OtherResult;
|
@ -2,12 +2,14 @@ import React, { useState, useEffect } from 'react';
|
||||
import { View, SafeAreaView } from 'react-native';
|
||||
import ScrollableTabView from 'react-native-scrollable-tab-view';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
// Components
|
||||
import { SearchInput, TabBar } from '../../../components';
|
||||
import Communities from './communities';
|
||||
import PostResult from './postResult';
|
||||
import OtherResult from './otherResults';
|
||||
import { SearchInput, TabBar, IconButton } from '../../../components';
|
||||
import Communities from './tabs/communities/view/communitiesResults';
|
||||
import PostsResults from './tabs/best/view/postsResults';
|
||||
import TopicsResults from './tabs/topics/view/topicsResults';
|
||||
import PeopleResults from './tabs/people/view/peopleResults';
|
||||
|
||||
// Styles
|
||||
import styles from './searchResultStyles';
|
||||
@ -15,17 +17,8 @@ import globalStyles from '../../../globalStyles';
|
||||
|
||||
const SearchResultScreen = ({ navigation }) => {
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [text, setText] = useState('');
|
||||
const intl = useIntl();
|
||||
|
||||
useEffect(() => {
|
||||
const delayDebounceFn = setTimeout(() => {
|
||||
setSearchValue(text);
|
||||
}, 100);
|
||||
|
||||
return () => clearTimeout(delayDebounceFn);
|
||||
}, [text]);
|
||||
|
||||
const _navigationGoBack = () => {
|
||||
navigation.goBack();
|
||||
};
|
||||
@ -36,38 +29,64 @@ const SearchResultScreen = ({ navigation }) => {
|
||||
tabUnderlineDefaultWidth={80}
|
||||
tabUnderlineScaleX={2}
|
||||
tabBarPosition="overlayTop"
|
||||
textStyle={styles.tabBarText}
|
||||
/>
|
||||
);
|
||||
|
||||
const _handleChangeText = debounce((value) => {
|
||||
setSearchValue(value);
|
||||
}, 250);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<SafeAreaView>
|
||||
<View style={styles.headerContainer}>
|
||||
<View style={{ flex: 11 }}>
|
||||
<SearchInput
|
||||
handleOnModalClose={_navigationGoBack}
|
||||
//handleOnModalClose={_navigationGoBack}
|
||||
placeholder={intl.formatMessage({ id: 'header.search' })}
|
||||
onChangeText={setText}
|
||||
onChangeText={_handleChangeText}
|
||||
/>
|
||||
</View>
|
||||
<View style={{ flex: 1, marginTop: 20 }}>
|
||||
<IconButton
|
||||
iconType="Ionicons"
|
||||
name="ios-close-circle-outline"
|
||||
iconStyle={styles.backIcon}
|
||||
onPress={_navigationGoBack}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
<ScrollableTabView
|
||||
style={globalStyles.tabView}
|
||||
renderTabBar={_renderTabbar}
|
||||
prerenderingSiblingsNumber={Infinity}
|
||||
>
|
||||
<View
|
||||
tabLabel={intl.formatMessage({ id: 'search_result.best.title' })}
|
||||
style={styles.tabbarItem}
|
||||
>
|
||||
<PostsResults searchValue={searchValue} />
|
||||
</View>
|
||||
<View
|
||||
tabLabel={intl.formatMessage({ id: 'search_result.people.title' })}
|
||||
style={styles.tabbarItem}
|
||||
>
|
||||
<PeopleResults searchValue={searchValue} />
|
||||
</View>
|
||||
<View
|
||||
tabLabel={intl.formatMessage({ id: 'search_result.topics.title' })}
|
||||
style={styles.tabbarItem}
|
||||
>
|
||||
<TopicsResults searchValue={searchValue} />
|
||||
</View>
|
||||
<View
|
||||
tabLabel={intl.formatMessage({ id: 'search_result.communities.title' })}
|
||||
style={styles.tabbarItem}
|
||||
>
|
||||
<Communities searchValue={searchValue} />
|
||||
</View>
|
||||
<View tabLabel={intl.formatMessage({ id: 'search.posts' })} style={styles.tabbarItem}>
|
||||
<PostResult searchValue={searchValue} />
|
||||
</View>
|
||||
<View
|
||||
tabLabel={intl.formatMessage({ id: 'search_result.others' })}
|
||||
style={styles.tabbarItem}
|
||||
>
|
||||
<OtherResult searchValue={searchValue} />
|
||||
</View>
|
||||
</ScrollableTabView>
|
||||
</View>
|
||||
);
|
||||
|
@ -5,6 +5,11 @@ export default EStyleSheet.create({
|
||||
flex: 1,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
},
|
||||
headerContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingRight: 12,
|
||||
},
|
||||
buttonContainer: {
|
||||
width: '50%',
|
||||
alignItems: 'center',
|
||||
@ -28,4 +33,12 @@ export default EStyleSheet.create({
|
||||
tabs: {
|
||||
flex: 1,
|
||||
},
|
||||
tabBarText: {
|
||||
fontSize: 14,
|
||||
},
|
||||
backIcon: {
|
||||
fontSize: 24,
|
||||
color: '$iconColor',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
});
|
||||
|
@ -0,0 +1,106 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import ROUTES from '../../../../../../constants/routeNames';
|
||||
|
||||
import { search, getPromotePosts } from '../../../../../../providers/ecency/ecency';
|
||||
import { getPost, getAccountPosts } from '../../../../../../providers/hive/dhive';
|
||||
|
||||
const PostsResultsContainer = ({ children, navigation, searchValue, currentAccountUsername }) => {
|
||||
const [data, setData] = useState([]);
|
||||
const [sort, setSort] = useState('newest');
|
||||
const [scrollId, setScrollId] = useState('');
|
||||
const [noResult, setNoResult] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setNoResult(false);
|
||||
setData([]);
|
||||
|
||||
if (searchValue) {
|
||||
search({ q: `${searchValue} type:post`, sort })
|
||||
.then((res) => {
|
||||
setScrollId(res.scroll_id);
|
||||
setData(res.results);
|
||||
if (res.results.length === 0) {
|
||||
setNoResult(true);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err, 'search error'));
|
||||
} else {
|
||||
getInitialPosts();
|
||||
}
|
||||
}, [searchValue]);
|
||||
|
||||
const getInitialPosts = async () => {
|
||||
// const promoteds = await getPromotePosts();
|
||||
// return await Promise.all(
|
||||
// promoteds.map(async (item) => {
|
||||
// const post = await getPost(
|
||||
// get(item, 'author'),
|
||||
// get(item, 'permlink'),
|
||||
// currentAccountUsername,
|
||||
// true,
|
||||
// );
|
||||
// post.author_rep = post.author_reputation;
|
||||
// post.body = (post.summary && post.summary.substring(0, 130)) || '';
|
||||
// // return await call to your function
|
||||
// return post;
|
||||
// }),
|
||||
// );
|
||||
try {
|
||||
const options = {
|
||||
observer: currentAccountUsername,
|
||||
account: 'ecency',
|
||||
limit: 7,
|
||||
sort: 'blog',
|
||||
};
|
||||
const _data = await getAccountPosts(options);
|
||||
|
||||
if (_data.length === 0) {
|
||||
setNoResult(true);
|
||||
}
|
||||
setData(_data);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Component Functions
|
||||
|
||||
const _handleOnPress = (item) => {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.POST,
|
||||
params: {
|
||||
author: get(item, 'author'),
|
||||
permlink: get(item, 'permlink'),
|
||||
},
|
||||
key: get(item, 'permlink'),
|
||||
});
|
||||
};
|
||||
|
||||
const _loadMore = (index, value) => {
|
||||
if (scrollId) {
|
||||
search({ q: `${searchValue} type:post`, sort, scroll_id: scrollId }).then((res) => {
|
||||
setData([...data, ...res.results]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
children &&
|
||||
children({
|
||||
data,
|
||||
handleOnPress: _handleOnPress,
|
||||
loadMore: _loadMore,
|
||||
noResult,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
currentAccountUsername: state.account.currentAccount.username,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withNavigation(PostsResultsContainer));
|
@ -6,28 +6,35 @@ import FastImage from 'react-native-fast-image';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
// Components
|
||||
import { PostHeaderDescription, FilterBar } from '../../../components';
|
||||
import { TextWithIcon, CommunitiesPlaceHolder } from '../../../components/basicUIElements';
|
||||
import PostResultContainer from '../container/postResultContainer';
|
||||
import { PostHeaderDescription, FilterBar } from '../../../../../../components';
|
||||
import {
|
||||
TextWithIcon,
|
||||
CommunitiesPlaceHolder,
|
||||
EmptyScreen,
|
||||
} from '../../../../../../components/basicUIElements';
|
||||
import PostsResultsContainer from '../container/postsResultsContainer';
|
||||
|
||||
import { getTimeFromNow } from '../../../utils/time';
|
||||
import { getTimeFromNow } from '../../../../../../utils/time';
|
||||
|
||||
import styles from './postResultStyles';
|
||||
import styles from './postsResultsStyles';
|
||||
|
||||
import DEFAULT_IMAGE from '../../../assets/no_image.png';
|
||||
import DEFAULT_IMAGE from '../../../../../../assets/no_image.png';
|
||||
|
||||
const filterOptions = ['relevance', 'popularity', 'newest'];
|
||||
|
||||
const PostResult = ({ navigation, searchValue }) => {
|
||||
const PostsResults = ({ navigation, searchValue }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const _renderItem = (item, index) => {
|
||||
const reputation =
|
||||
get(item, 'author_rep', undefined) || get(item, 'author_reputation', undefined);
|
||||
|
||||
return (
|
||||
<View style={[styles.itemWrapper, index % 2 !== 0 && styles.itemWrapperGray]}>
|
||||
<PostHeaderDescription
|
||||
date={getTimeFromNow(get(item, 'created_at'))}
|
||||
name={get(item, 'author')}
|
||||
reputation={Math.floor(get(item, 'author_rep'))}
|
||||
reputation={Math.floor(reputation)}
|
||||
size={36}
|
||||
tag={item.category}
|
||||
/>
|
||||
@ -78,25 +85,15 @@ const PostResult = ({ navigation, searchValue }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<PostResultContainer searchValue={searchValue}>
|
||||
{({ data, filterIndex, handleFilterChanged, handleOnPress, loadMore }) => (
|
||||
<PostsResultsContainer searchValue={searchValue}>
|
||||
{({ data, handleOnPress, loadMore, noResult }) => (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<FilterBar
|
||||
dropdownIconName="arrow-drop-down"
|
||||
options={filterOptions.map((item) =>
|
||||
intl.formatMessage({
|
||||
id: `search_result.post_result_filter.${item}`,
|
||||
}),
|
||||
)}
|
||||
defaultText={intl.formatMessage({
|
||||
id: `search_result.post_result_filter.${filterOptions[filterIndex]}`,
|
||||
})}
|
||||
selectedOptionIndex={filterIndex}
|
||||
onDropdownSelect={(index) => handleFilterChanged(index, filterOptions[index])}
|
||||
/>
|
||||
{noResult ? (
|
||||
<EmptyScreen />
|
||||
) : (
|
||||
<FlatList
|
||||
data={data}
|
||||
keyExtractor={(item) => item.id && item.id.toString()}
|
||||
keyExtractor={(item, index) => index.toString()}
|
||||
renderItem={({ item, index }) => (
|
||||
<TouchableOpacity onPress={() => handleOnPress(item)}>
|
||||
{_renderItem(item, index)}
|
||||
@ -106,10 +103,11 @@ const PostResult = ({ navigation, searchValue }) => {
|
||||
ListEmptyComponent={_renderEmptyContent}
|
||||
ListFooterComponent={<CommunitiesPlaceHolder />}
|
||||
/>
|
||||
)}
|
||||
</SafeAreaView>
|
||||
)}
|
||||
</PostResultContainer>
|
||||
</PostsResultsContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default PostResult;
|
||||
export default PostsResults;
|
@ -0,0 +1,150 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { shuffle } from 'lodash';
|
||||
|
||||
import ROUTES from '../../../../../../constants/routeNames';
|
||||
|
||||
import { getCommunities, getSubscriptions } from '../../../../../../providers/hive/dhive';
|
||||
|
||||
import {
|
||||
subscribeCommunity,
|
||||
leaveCommunity,
|
||||
} from '../../../../../../redux/actions/communitiesAction';
|
||||
|
||||
// const DEFAULT_COMMUNITIES = [
|
||||
// 'hive-125125',
|
||||
// 'hive-174301',
|
||||
// 'hive-140217',
|
||||
// 'hive-179017',
|
||||
// 'hive-160545',
|
||||
// 'hive-194913',
|
||||
// 'hive-166847',
|
||||
// 'hive-176853',
|
||||
// 'hive-183196',
|
||||
// 'hive-163772',
|
||||
// 'hive-106444',
|
||||
// ];
|
||||
|
||||
const CommunitiesResultsContainer = ({ children, navigation, searchValue }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [data, setData] = useState([]);
|
||||
const [noResult, setNoResult] = useState(false);
|
||||
|
||||
const pinCode = useSelector((state) => state.application.pin);
|
||||
const currentAccount = useSelector((state) => state.account.currentAccount);
|
||||
const isLoggedIn = useSelector((state) => state.application.isLoggedIn);
|
||||
const subscribingCommunities = useSelector(
|
||||
(state) => state.communities.subscribingCommunitiesInSearchResultsScreen,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setData([]);
|
||||
setNoResult(false);
|
||||
|
||||
getSubscriptions(currentAccount.username).then((subs) => {
|
||||
getCommunities('', searchValue ? 100 : 20, searchValue, 'rank').then((communities) => {
|
||||
communities.forEach((community) =>
|
||||
Object.assign(community, {
|
||||
isSubscribed: subs.some(
|
||||
(subscribedCommunity) => subscribedCommunity[0] === community.name,
|
||||
),
|
||||
}),
|
||||
);
|
||||
|
||||
if (searchValue) {
|
||||
setData(communities);
|
||||
} else {
|
||||
setData(shuffle(communities));
|
||||
}
|
||||
|
||||
if (communities.length === 0) {
|
||||
setNoResult(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}, [searchValue]);
|
||||
|
||||
useEffect(() => {
|
||||
const communitiesData = [...data];
|
||||
|
||||
Object.keys(subscribingCommunities).map((communityId) => {
|
||||
if (!subscribingCommunities[communityId].loading) {
|
||||
if (!subscribingCommunities[communityId].error) {
|
||||
if (subscribingCommunities[communityId].isSubscribed) {
|
||||
communitiesData.forEach((item) => {
|
||||
if (item.name === communityId) {
|
||||
item.isSubscribed = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
communitiesData.forEach((item) => {
|
||||
if (item.name === communityId) {
|
||||
item.isSubscribed = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setData(communitiesData);
|
||||
}, [subscribingCommunities]);
|
||||
|
||||
// Component Functions
|
||||
const _handleOnPress = (name) => {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.COMMUNITY,
|
||||
params: {
|
||||
tag: name,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const _handleSubscribeButtonPress = (_data, screen) => {
|
||||
let subscribeAction;
|
||||
let successToastText = '';
|
||||
let failToastText = '';
|
||||
|
||||
if (!_data.isSubscribed) {
|
||||
subscribeAction = subscribeCommunity;
|
||||
|
||||
successToastText = intl.formatMessage({
|
||||
id: 'alert.success_subscribe',
|
||||
});
|
||||
failToastText = intl.formatMessage({
|
||||
id: 'alert.fail_subscribe',
|
||||
});
|
||||
} else {
|
||||
subscribeAction = leaveCommunity;
|
||||
|
||||
successToastText = intl.formatMessage({
|
||||
id: 'alert.success_leave',
|
||||
});
|
||||
failToastText = intl.formatMessage({
|
||||
id: 'alert.fail_leave',
|
||||
});
|
||||
}
|
||||
|
||||
dispatch(
|
||||
subscribeAction(currentAccount, pinCode, _data, successToastText, failToastText, screen),
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
children &&
|
||||
children({
|
||||
data,
|
||||
subscribingCommunities,
|
||||
handleOnPress: _handleOnPress,
|
||||
handleSubscribeButtonPress: _handleSubscribeButtonPress,
|
||||
isLoggedIn,
|
||||
noResult,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
export default withNavigation(CommunitiesResultsContainer);
|
@ -0,0 +1,40 @@
|
||||
import React from 'react';
|
||||
import get from 'lodash/get';
|
||||
|
||||
// Components
|
||||
import { CommunitiesList, EmptyScreen } from '../../../../../../components';
|
||||
|
||||
import CommunitiesResultsContainer from '../container/communitiesResultsContainer';
|
||||
|
||||
const CommunitiesResultsScreen = ({ navigation, searchValue }) => {
|
||||
const activeVotes = get(navigation, 'state.params.activeVotes');
|
||||
|
||||
return (
|
||||
<CommunitiesResultsContainer data={activeVotes} searchValue={searchValue}>
|
||||
{({
|
||||
data,
|
||||
subscribingCommunities,
|
||||
handleOnPress,
|
||||
handleSubscribeButtonPress,
|
||||
isLoggedIn,
|
||||
noResult,
|
||||
}) =>
|
||||
noResult ? (
|
||||
<EmptyScreen />
|
||||
) : (
|
||||
<CommunitiesList
|
||||
data={data}
|
||||
subscribingCommunities={subscribingCommunities}
|
||||
handleOnPress={handleOnPress}
|
||||
handleSubscribeButtonPress={handleSubscribeButtonPress}
|
||||
isLoggedIn={isLoggedIn}
|
||||
noResult={noResult}
|
||||
screen="searchResultsScreen"
|
||||
/>
|
||||
)
|
||||
}
|
||||
</CommunitiesResultsContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default CommunitiesResultsScreen;
|
@ -0,0 +1,65 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import ROUTES from '../../../../../../constants/routeNames';
|
||||
|
||||
import { lookupAccounts } from '../../../../../../providers/hive/dhive';
|
||||
import { getLeaderboard } from '../../../../../../providers/ecency/ecency';
|
||||
|
||||
const PeopleResultsContainer = (props) => {
|
||||
const [users, setUsers] = useState([]);
|
||||
const [noResult, setNoResult] = useState(false);
|
||||
|
||||
const { children, navigation, searchValue, username } = props;
|
||||
|
||||
useEffect(() => {
|
||||
setNoResult(false);
|
||||
setUsers([]);
|
||||
|
||||
if (searchValue) {
|
||||
lookupAccounts(searchValue).then((res) => {
|
||||
if (res.length === 0) {
|
||||
setNoResult(true);
|
||||
}
|
||||
setUsers(res);
|
||||
});
|
||||
} else {
|
||||
getLeaderboard().then((result) => {
|
||||
const sos = result.map((item) => item._id);
|
||||
if (sos.length === 0) {
|
||||
setNoResult(true);
|
||||
}
|
||||
setUsers(sos);
|
||||
});
|
||||
}
|
||||
}, [searchValue]);
|
||||
|
||||
// Component Functions
|
||||
|
||||
const _handleOnPress = (item) => {
|
||||
navigation.navigate({
|
||||
routeName: item === username ? ROUTES.TABBAR.PROFILE : ROUTES.SCREENS.PROFILE,
|
||||
params: {
|
||||
username: item,
|
||||
},
|
||||
key: item.text,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
children &&
|
||||
children({
|
||||
users,
|
||||
handleOnPress: _handleOnPress,
|
||||
noResult,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
username: state.account.currentAccount.name,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withNavigation(PeopleResultsContainer));
|
@ -0,0 +1,52 @@
|
||||
import React from 'react';
|
||||
import { SafeAreaView, FlatList } from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
// Components
|
||||
import {
|
||||
ListPlaceHolder,
|
||||
EmptyScreen,
|
||||
UserListItem,
|
||||
} from '../../../../../../components/basicUIElements';
|
||||
import PeopleResultsContainer from '../container/peopleResultsContainer';
|
||||
|
||||
import styles from './peopleResultsStyles';
|
||||
|
||||
const PeopleResults = ({ navigation, searchValue }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const _renderEmptyContent = () => {
|
||||
return (
|
||||
<>
|
||||
<ListPlaceHolder />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<PeopleResultsContainer searchValue={searchValue}>
|
||||
{({ users, handleOnPress, noResult }) => (
|
||||
<SafeAreaView style={styles.container}>
|
||||
{noResult ? (
|
||||
<EmptyScreen />
|
||||
) : (
|
||||
<FlatList
|
||||
data={users}
|
||||
keyExtractor={(item, index) => index.toString()}
|
||||
renderItem={({ item, index }) => (
|
||||
<UserListItem
|
||||
handleOnPress={() => handleOnPress(item)}
|
||||
index={index}
|
||||
username={item}
|
||||
/>
|
||||
)}
|
||||
ListEmptyComponent={_renderEmptyContent}
|
||||
/>
|
||||
)}
|
||||
</SafeAreaView>
|
||||
)}
|
||||
</PeopleResultsContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default PeopleResults;
|
@ -0,0 +1,57 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import get from 'lodash/get';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import ROUTES from '../../../../../../constants/routeNames';
|
||||
|
||||
import { getTrendingTags } from '../../../../../../providers/hive/dhive';
|
||||
import { getLeaderboard } from '../../../../../../providers/ecency/ecency';
|
||||
import { isCommunity } from '../../../../../../utils/communityValidation';
|
||||
|
||||
const OtherResultContainer = (props) => {
|
||||
const [tags, setTags] = useState([]);
|
||||
const [noResult, setNoResult] = useState(false);
|
||||
|
||||
const { children, navigation, searchValue } = props;
|
||||
|
||||
useEffect(() => {
|
||||
if (searchValue.length <= 10) {
|
||||
setNoResult(false);
|
||||
setTags([]);
|
||||
getTrendingTags(searchValue.trim(), 100).then((res) => {
|
||||
const data = res?.filter((item) => !isCommunity(item.name));
|
||||
if (data.length === 0) {
|
||||
setNoResult(true);
|
||||
}
|
||||
setTags(data);
|
||||
});
|
||||
}
|
||||
}, [searchValue]);
|
||||
|
||||
// Component Functions
|
||||
|
||||
const _handleOnPress = (item) => {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.TAG_RESULT,
|
||||
params: {
|
||||
tag: get(item, 'name', ''),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
children &&
|
||||
children({
|
||||
tags,
|
||||
handleOnPress: _handleOnPress,
|
||||
noResult,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
username: state.account.currentAccount.name,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(withNavigation(OtherResultContainer));
|
@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { SafeAreaView, FlatList, View, Text, TouchableOpacity } from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
// Components
|
||||
import { ListPlaceHolder, EmptyScreen } from '../../../../../../components/basicUIElements';
|
||||
import TopicsResultsContainer from '../container/topicsResultsContainer';
|
||||
|
||||
import styles from './topicsResultsStyles';
|
||||
|
||||
const filterOptions = ['user', 'tag'];
|
||||
|
||||
const TopicsResults = ({ navigation, searchValue }) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const _renderTagItem = (item, index) => (
|
||||
<View style={[styles.itemWrapper, index % 2 !== 0 && styles.itemWrapperGray]}>
|
||||
<Text style={styles.username}>{`#${item.name}`}</Text>
|
||||
</View>
|
||||
);
|
||||
|
||||
const _renderEmptyContent = () => {
|
||||
return (
|
||||
<>
|
||||
<ListPlaceHolder />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<TopicsResultsContainer searchValue={searchValue}>
|
||||
{({ tags, handleOnPress, noResult }) => (
|
||||
<SafeAreaView style={styles.container}>
|
||||
{noResult ? (
|
||||
<EmptyScreen />
|
||||
) : (
|
||||
<FlatList
|
||||
data={tags}
|
||||
keyExtractor={(item, index) => index.toString()}
|
||||
renderItem={({ item, index }) => (
|
||||
<TouchableOpacity onPress={() => handleOnPress(item)}>
|
||||
{_renderTagItem(item, index)}
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
ListEmptyComponent={_renderEmptyContent}
|
||||
/>
|
||||
)}
|
||||
</SafeAreaView>
|
||||
)}
|
||||
</TopicsResultsContainer>
|
||||
);
|
||||
};
|
||||
|
||||
export default TopicsResults;
|
@ -0,0 +1,48 @@
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
},
|
||||
itemWrapper: {
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 16,
|
||||
paddingBottom: 8,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
},
|
||||
itemWrapperGray: {
|
||||
backgroundColor: '$primaryLightBackground',
|
||||
},
|
||||
username: {
|
||||
marginLeft: 10,
|
||||
color: '$primaryBlack',
|
||||
},
|
||||
communityWrapper: {
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
},
|
||||
subscribeButton: {
|
||||
maxWidth: 75,
|
||||
borderWidth: 1,
|
||||
borderColor: '$primaryBlue',
|
||||
},
|
||||
subscribeButtonText: {
|
||||
textAlign: 'center',
|
||||
color: '$primaryBlue',
|
||||
},
|
||||
community: {
|
||||
justifyContent: 'center',
|
||||
marginLeft: 15,
|
||||
color: '$primaryBlack',
|
||||
},
|
||||
});
|
@ -1,5 +1,7 @@
|
||||
import { isNumber } from 'lodash';
|
||||
|
||||
export const isCommunity = (text) => {
|
||||
if (/^hive-\d+/.test(text) && text.length === 11) {
|
||||
if (/hive-[1-3]\d{4,6}$/.test(text) && isNumber(Number(text.split('-')[1]))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -63,14 +63,16 @@ export const catchEntryImage = (entry, width = 0, height = 0, format = 'match')
|
||||
return null;
|
||||
};
|
||||
|
||||
export const catchDraftImage = (body, format = 'match') => {
|
||||
export const catchDraftImage = (body, format = 'match', thumbnail = false) => {
|
||||
const imgRegex = /(https?:\/\/.*\.(?:tiff?|jpe?g|gif|png|svg|ico|PNG|GIF|JPG))/g;
|
||||
format = whatOs === 'android' ? 'webp' : 'match';
|
||||
|
||||
if (body && imgRegex.test(body)) {
|
||||
const imageMatch = body.match(imgRegex);
|
||||
|
||||
return proxifyImageSrc(imageMatch[0], 0, 0, format);
|
||||
if (thumbnail) {
|
||||
return proxifyImageSrc(imageMatch[0], 60, 50, format);
|
||||
}
|
||||
return proxifyImageSrc(imageMatch[0], 600, 500, format);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
@ -13,13 +13,13 @@ const webp = Platform.OS === 'ios' ? false : true;
|
||||
|
||||
export const parsePosts = (posts, currentUserName) => {
|
||||
if (posts) {
|
||||
const formattedPosts = posts.map((post) => parsePost(post, currentUserName));
|
||||
const formattedPosts = posts.map((post) => parsePost(post, currentUserName, false, true));
|
||||
return formattedPosts;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const parsePost = (post, currentUserName, isPromoted) => {
|
||||
export const parsePost = (post, currentUserName, isPromoted, isList = false) => {
|
||||
if (!post) {
|
||||
return null;
|
||||
}
|
||||
@ -33,10 +33,12 @@ export const parsePost = (post, currentUserName, isPromoted) => {
|
||||
post.json_metadata = {};
|
||||
}
|
||||
post.image = catchPostImage(post.body, 600, 500, webp ? 'webp' : 'match');
|
||||
post.thumbnail = catchPostImage(post.body, 60, 50, webp ? 'webp' : 'match');
|
||||
post.author_reputation = getReputation(post.author_reputation);
|
||||
post.avatar = getResizedAvatar(get(post, 'author'));
|
||||
|
||||
if (!isList) {
|
||||
post.body = renderPostBody(post, true, webp);
|
||||
}
|
||||
post.summary = postBodySummary(post, 150);
|
||||
post.is_declined_payout = parseAsset(post.max_accepted_payout).amount === 0;
|
||||
|
||||
|
@ -81,11 +81,7 @@ export const groomingTransactionData = (transaction, steemPerMVests) => {
|
||||
}
|
||||
break;
|
||||
case 'claim_reward_balance':
|
||||
let {
|
||||
reward_sbd: rewardSdb = opData.reward_hbd,
|
||||
reward_steem: rewardSteem = opData.reward_hive,
|
||||
reward_vests: rewardVests,
|
||||
} = opData;
|
||||
let { reward_hbd: rewardSdb, reward_hive: rewardSteem, reward_vests: rewardVests } = opData;
|
||||
|
||||
rewardSdb = parseToken(rewardSdb).toFixed(3).replace(',', '.');
|
||||
rewardSteem = parseToken(rewardSteem).toFixed(3).replace(',', '.');
|
||||
@ -192,15 +188,9 @@ export const groomingWalletData = async (user, globalProps, userCurrency) => {
|
||||
const [userdata] = state;
|
||||
|
||||
// TODO: move them to utils these so big for a lifecycle function
|
||||
walletData.rewardSteemBalance = parseToken(
|
||||
userdata.reward_hive_balance || userdata.reward_steem_balance,
|
||||
);
|
||||
walletData.rewardSbdBalance = parseToken(
|
||||
userdata.reward_hbd_balance || userdata.reward_sbd_balance,
|
||||
);
|
||||
walletData.rewardVestingSteem = parseToken(
|
||||
userdata.reward_vesting_hive || userdata.reward_vesting_steem,
|
||||
);
|
||||
walletData.rewardSteemBalance = parseToken(userdata.reward_hive_balance);
|
||||
walletData.rewardSbdBalance = parseToken(userdata.reward_hbd_balance);
|
||||
walletData.rewardVestingSteem = parseToken(userdata.reward_vesting_hive);
|
||||
walletData.hasUnclaimedRewards =
|
||||
walletData.rewardSteemBalance > 0 ||
|
||||
walletData.rewardSbdBalance > 0 ||
|
||||
@ -211,11 +201,9 @@ export const groomingWalletData = async (user, globalProps, userCurrency) => {
|
||||
walletData.vestingSharesReceived = parseToken(userdata.received_vesting_shares);
|
||||
walletData.vestingSharesTotal =
|
||||
walletData.vestingShares - walletData.vestingSharesDelegated + walletData.vestingSharesReceived;
|
||||
walletData.sbdBalance = parseToken(userdata.hbd_balance || userdata.sbd_balance);
|
||||
walletData.sbdBalance = parseToken(userdata.hbd_balance);
|
||||
walletData.savingBalance = parseToken(userdata.savings_balance);
|
||||
walletData.savingBalanceSbd = parseToken(
|
||||
userdata.savings_hbd_balance || userdata.savings_sbd_balance,
|
||||
);
|
||||
walletData.savingBalanceSbd = parseToken(userdata.savings_hbd_balance);
|
||||
|
||||
const feedHistory = await getFeedHistory();
|
||||
const base = parseToken(feedHistory.current_median_history.base);
|
||||
|
21
yarn.lock
21
yarn.lock
@ -698,10 +698,10 @@
|
||||
exec-sh "^0.3.2"
|
||||
minimist "^1.2.0"
|
||||
|
||||
"@ecency/render-helper@^2.0.11":
|
||||
version "2.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@ecency/render-helper/-/render-helper-2.0.11.tgz#faa140a318aa6c2a693cfb3d21f3e8b1821cdb8e"
|
||||
integrity sha512-g9lDtdB3yrta3pHQodPQQbFIkg3kCrVvcKhrqUrl2JY0hYreKUlmRzGWobJFphyAoXnUubrTW/l8p4N3hUwteg==
|
||||
"@ecency/render-helper@^2.0.15":
|
||||
version "2.0.15"
|
||||
resolved "https://registry.yarnpkg.com/@ecency/render-helper/-/render-helper-2.0.15.tgz#8e78a2d771d44dc6e77bf63bbf786589cf11a772"
|
||||
integrity sha512-II3TAdSy3pCqcuWgL81ZJ8N8jVrQR5rosxA8kGc40/vHeoDPhgLmUUxmykJVZUubejOTtowyIpjSu8g7sJkXRg==
|
||||
dependencies:
|
||||
he "^1.2.0"
|
||||
lru-cache "^5.1.1"
|
||||
@ -7574,16 +7574,21 @@ react-native-iap@3.4.15:
|
||||
dependencies:
|
||||
dooboolab-welcome "^1.1.1"
|
||||
|
||||
react-native-image-crop-picker@^0.26.1:
|
||||
version "0.26.2"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.26.2.tgz#c70985ff6740e63569f90b185be0516d83f5933b"
|
||||
integrity sha512-KnPtSJklwXr/BNdcyAlDp9xkDCQyJ5ZA4dM10elBc2aIXac/4CndbiPFZrwu4GlAYYYKlkiTTwTYW+h4RyGLaw==
|
||||
react-native-image-crop-picker@^0.35.2:
|
||||
version "0.35.2"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-crop-picker/-/react-native-image-crop-picker-0.35.2.tgz#21e085e40cb5724e1e986b8eba59ef23df19598c"
|
||||
integrity sha512-4nHAYwnemFJLzVJPl5dhNB+WQgNp41MLJjyYCypatMZl2GJD+EVXnu5eSUQE+UOpaIEhSVtqK5Y3OQ93hMhosQ==
|
||||
|
||||
react-native-image-pan-zoom@^2.1.9:
|
||||
version "2.1.12"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.12.tgz#eb98bf56fb5610379bdbfdb63219cc1baca98fd2"
|
||||
integrity sha512-BF66XeP6dzuANsPmmFsJshM2Jyh/Mo1t8FsGc1L9Q9/sVP8MJULDabB1hms+eAoqgtyhMr5BuXV3E1hJ5U5H6Q==
|
||||
|
||||
react-native-image-size@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-size/-/react-native-image-size-1.1.3.tgz#7d69c2cd4e1d1632947867e47643ed8cabb9de27"
|
||||
integrity sha512-jJvN6CjXVAm69LAVZNV7m7r50Qk9vuPZwLyrbs/k31/3Xs8bZyVCdvfP44FuBisITn/yFsiOo6i8NPrFBPH20w==
|
||||
|
||||
react-native-image-zoom-viewer@^2.2.27:
|
||||
version "2.2.27"
|
||||
resolved "https://registry.yarnpkg.com/react-native-image-zoom-viewer/-/react-native-image-zoom-viewer-2.2.27.tgz#fb3314c5dc86ac33da48cb31bf4920d97eecb6eb"
|
||||
|
Loading…
Reference in New Issue
Block a user