mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-18 10:52:16 +03:00
commit
09d05f59ac
@ -442,7 +442,7 @@ PODS:
|
||||
- React-Core
|
||||
- RNScreens (2.18.1):
|
||||
- React-Core
|
||||
- RNSVG (9.13.6):
|
||||
- RNSVG (12.1.1):
|
||||
- React
|
||||
- RNVectorIcons (6.7.0):
|
||||
- React
|
||||
@ -761,7 +761,7 @@ SPEC CHECKSUMS:
|
||||
RNOS: 6f2f9a70895bbbfbdad7196abd952e7b01d45027
|
||||
RNReanimated: e03f7425cb7a38dcf1b644d680d1bfc91c3337ad
|
||||
RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d
|
||||
RNSVG: 8ba35cbeb385a52fd960fd28db9d7d18b4c2974f
|
||||
RNSVG: 551acb6562324b1d52a4e0758f7ca0ec234e278f
|
||||
RNVectorIcons: 368d6d8b8301224e5ffb6254191f4f8876c2be0d
|
||||
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
|
||||
SDWebImageWebPCoder: d0dac55073088d24b2ac1b191a71a8f8d0adac21
|
||||
|
@ -105,6 +105,7 @@
|
||||
"react-native-modal-translucent": "^5.0.0",
|
||||
"react-native-navigation-bar-color": "^1.0.0",
|
||||
"react-native-os": "^1.0.1",
|
||||
"react-native-progress": "^5.0.0",
|
||||
"react-native-push-notification": "^7.3.1",
|
||||
"react-native-qrcode-svg": "^6.0.3",
|
||||
"react-native-randombytes": "^3.6.1",
|
||||
@ -117,7 +118,7 @@
|
||||
"react-native-scrollable-tab-view": "ecency/react-native-scrollable-tab-view",
|
||||
"react-native-snap-carousel": "^3.8.0",
|
||||
"react-native-splash-screen": "^3.2.0",
|
||||
"react-native-svg": "^9.5.3",
|
||||
"react-native-svg": "^12.1.1",
|
||||
"react-native-swiper": "^1.6.0-rc.3",
|
||||
"react-native-tcp": "^3.2.1",
|
||||
"react-native-udp": "^2.1.0",
|
||||
|
@ -7,6 +7,7 @@ import FontAwesome from 'react-native-vector-icons/FontAwesome';
|
||||
import Feather from 'react-native-vector-icons/Feather';
|
||||
import AntDesign from 'react-native-vector-icons/AntDesign';
|
||||
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
||||
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
|
||||
|
||||
import styles from './iconStyles';
|
||||
|
||||
@ -46,6 +47,8 @@ class IconView extends PureComponent {
|
||||
return <Feather {...this.props} />;
|
||||
case 'FontAwesome':
|
||||
return <FontAwesome {...this.props} />;
|
||||
case 'FontAwesome5':
|
||||
return <FontAwesome5 {...this.props} />;
|
||||
case 'SimpleLineIcons':
|
||||
return <SimpleLineIcons {...this.props}>{children}</SimpleLineIcons>;
|
||||
case 'AntDesign':
|
||||
|
@ -91,6 +91,7 @@ import { ActionModal } from './actionModal';
|
||||
import { CustomiseFiltersModal } from './customiseFiltersModal';
|
||||
import { ForegroundNotification } from './foregroundNotification';
|
||||
import { PostHtmlRenderer } from './postHtmlRenderer';
|
||||
import { QuickProfileModal } from './organisms';
|
||||
|
||||
// Basic UI Elements
|
||||
import {
|
||||
@ -230,4 +231,5 @@ export {
|
||||
CustomiseFiltersModal,
|
||||
ForegroundNotification,
|
||||
PostHtmlRenderer,
|
||||
QuickProfileModal,
|
||||
};
|
||||
|
@ -188,6 +188,7 @@ class NotificationView extends PureComponent {
|
||||
<NotificationLine
|
||||
notification={item}
|
||||
handleOnPressNotification={this.props.navigateToNotificationRoute}
|
||||
handleOnUserPress={()=>{this.props.handleOnUserPress(item.source)}}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* eslint-disable react/jsx-one-expression-per-line */
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { View, Text, Image, TouchableHighlight } from 'react-native';
|
||||
import { View, Text, Image, TouchableHighlight, TouchableOpacity } from 'react-native';
|
||||
import { useIntl } from 'react-intl';
|
||||
import get from 'lodash/get';
|
||||
|
||||
@ -10,7 +10,7 @@ import { UserAvatar } from '../../userAvatar';
|
||||
// Styles
|
||||
import styles from './notificationLineStyles';
|
||||
|
||||
const NotificationLineView = ({ notification, handleOnPressNotification }) => {
|
||||
const NotificationLineView = ({ notification, handleOnPressNotification, handleOnUserPress }) => {
|
||||
const [isRead, setIsRead] = useState(notification.read);
|
||||
const intl = useIntl();
|
||||
let _title;
|
||||
@ -58,10 +58,14 @@ const NotificationLineView = ({ notification, handleOnPressNotification }) => {
|
||||
key={`${get(notification, 'id')}${_title}`}
|
||||
style={[styles.notificationWrapper, !isRead && styles.isNewNotification]}
|
||||
>
|
||||
<TouchableOpacity onPress={handleOnUserPress}>
|
||||
<UserAvatar
|
||||
noAction={true}
|
||||
username={notification.source}
|
||||
style={[styles.avatar, !notification.avatar && styles.hasNoAvatar]}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.body}>
|
||||
<View style={styles.titleWrapper}>
|
||||
<Text style={styles.name}>{notification.source} </Text>
|
||||
|
1
src/components/organisms/index.ts
Normal file
1
src/components/organisms/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './quickProfileModal';
|
@ -0,0 +1,45 @@
|
||||
import * as React from 'react';
|
||||
import { Text, View, StyleSheet } from 'react-native';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { IconButton } from '../../..';
|
||||
import { useAppSelector } from '../../../../hooks';
|
||||
import styles from './quickProfileStyles';
|
||||
|
||||
interface ActionPanelProps {
|
||||
isFollowing:boolean,
|
||||
isFavourite:boolean,
|
||||
onFollowPress:()=>void,
|
||||
onFavouritePress:()=>void
|
||||
}
|
||||
|
||||
export const ActionPanel = ({isFollowing, isFavourite, onFavouritePress, onFollowPress}: ActionPanelProps) => {
|
||||
|
||||
const heartColor = isFavourite
|
||||
? '$primaryRed'
|
||||
: '$primaryDarkGray'
|
||||
|
||||
const followIcon = isFollowing
|
||||
? 'user-check'
|
||||
: 'user-plus'
|
||||
|
||||
return (
|
||||
<View style={styles.actionPanel}>
|
||||
<IconButton
|
||||
iconType='FontAwesome5'
|
||||
name={followIcon}
|
||||
size={20}
|
||||
color={EStyleSheet.value('$primaryDarkGray')}
|
||||
disabled={isFollowing}
|
||||
onPress={onFollowPress}
|
||||
/>
|
||||
<IconButton
|
||||
style={{marginLeft:8}}
|
||||
iconType='AntDesign'
|
||||
name={'heart'}
|
||||
size={20}
|
||||
color={EStyleSheet.value(heartColor)}
|
||||
onPress={onFavouritePress}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
@ -0,0 +1 @@
|
||||
export * from './quickProfileContent';
|
@ -0,0 +1,61 @@
|
||||
import React from 'react'
|
||||
import { View, Text, TouchableOpacity } from 'react-native'
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import styles from './quickProfileStyles';
|
||||
import * as Progress from 'react-native-progress';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
interface Props {
|
||||
avatarUrl:string,
|
||||
username:string,
|
||||
about:string,
|
||||
created:{
|
||||
unit:string,
|
||||
value:number
|
||||
},
|
||||
votingPower:string,
|
||||
isLoading:boolean,
|
||||
onPress:()=>void
|
||||
}
|
||||
|
||||
export const ProfileBasic = ({avatarUrl, username, about, votingPower, isLoading, created, onPress}: Props) => {
|
||||
const intl = useIntl();
|
||||
const progress = parseInt(votingPower || '0')/100;
|
||||
|
||||
let joinedString = '---'
|
||||
if(created){
|
||||
const timeString = `${(-created.value)} ${intl.formatMessage({id:`time.${created.unit}`})}`;
|
||||
joinedString = intl.formatMessage({id:'profile.joined'}, {time:timeString})
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={onPress} >
|
||||
<View style={styles.container}>
|
||||
<View>
|
||||
<FastImage
|
||||
source={{uri:avatarUrl}}
|
||||
resizeMode='cover'
|
||||
style={styles.image}
|
||||
/>
|
||||
<View style={styles.progressCircle}>
|
||||
<Progress.Circle
|
||||
size={144}
|
||||
indeterminate={isLoading}
|
||||
progress={progress}
|
||||
borderColor='gray'
|
||||
borderWidth={0}
|
||||
thickness={8}
|
||||
strokeCap='round'
|
||||
color={EStyleSheet.value('$primaryBlue')}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={styles.title}>{`@${username}`}</Text>
|
||||
<Text style={styles.bodyText} numberOfLines={2} >{about}</Text>
|
||||
<Text style={styles.bodyText}>{joinedString}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import React from 'react'
|
||||
import { View, Text } from 'react-native'
|
||||
import styles from './quickProfileStyles'
|
||||
import * as Animated from 'react-native-animatable'
|
||||
|
||||
|
||||
export interface StatsData {
|
||||
label:string,
|
||||
value:number|string,
|
||||
suffix?:string
|
||||
}
|
||||
|
||||
interface Props {
|
||||
data:StatsData[],
|
||||
horizontalMargin?:number
|
||||
}
|
||||
|
||||
export const ProfileStats = ({data, horizontalMargin}: Props) => {
|
||||
return (
|
||||
<View style={{flexDirection:'row', justifyContent:'space-around', marginTop:40, marginHorizontal:horizontalMargin }}>
|
||||
{data.map((item)=><StatItem label={item.label} value={item.value && (item.value + (item.suffix || ''))}/>)}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const StatItem = (props:{label:string, value:number|string}) => (
|
||||
<View style={{alignItems:'center', flex:1}}>
|
||||
{!!props.value ? (
|
||||
<Animated.Text animation='bounceIn' style={styles.statValue}>{props.value}</Animated.Text>
|
||||
):(
|
||||
<Text style={styles.statValue}>{'--'}</Text>
|
||||
)}
|
||||
|
||||
<Text style={styles.statLabel}>{props.label}</Text>
|
||||
</View>
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,273 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { useIntl } from 'react-intl'
|
||||
import { View, Alert } from 'react-native'
|
||||
import { ProfileStats, StatsData } from './profileStats'
|
||||
import { MainButton } from '../../..'
|
||||
import { addFavorite, checkFavorite, deleteFavorite } from '../../../../providers/ecency/ecency'
|
||||
import { followUser, getFollows, getRelationship, getUser } from '../../../../providers/hive/dhive'
|
||||
import { getRcPower, getVotingPower } from '../../../../utils/manaBar'
|
||||
import styles from './quickProfileStyles'
|
||||
import { ProfileBasic } from './profileBasic'
|
||||
import { parseReputation } from '../../../../utils/user'
|
||||
import { default as ROUTES } from '../../../../constants/routeNames';
|
||||
import { ActionPanel } from './actionPanel'
|
||||
import { getTimeFromNowNative } from '../../../../utils/time'
|
||||
import { useAppDispatch, useAppSelector } from '../../../../hooks'
|
||||
import { toastNotification } from '../../../../redux/actions/uiAction'
|
||||
import Bugsnag from '@bugsnag/react-native'
|
||||
|
||||
interface QuickProfileContentProps {
|
||||
username:string,
|
||||
navigation:any;
|
||||
onClose:()=>void;
|
||||
}
|
||||
|
||||
export const QuickProfileContent = ({
|
||||
username,
|
||||
navigation,
|
||||
onClose
|
||||
}:QuickProfileContentProps) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const currentAccount = useAppSelector((state)=>state.account.currentAccount);
|
||||
const pinCode = useAppSelector((state)=>state.application.pin);
|
||||
const isLoggedIn = useAppSelector((state)=>state.application.isLoggedIn);
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [user, setUser] = useState(null);
|
||||
const [follows, setFollows] = useState(null);
|
||||
const [isFollowing, setIsFollowing] = useState(false);
|
||||
const [isMuted, setIsMuted] = useState(false);
|
||||
const [isFavourite, setIsFavourite] = useState(false);
|
||||
|
||||
const isOwnProfile = currentAccount && currentAccount.name === username;
|
||||
const currentAccountName = currentAccount ? currentAccount.name : null;
|
||||
|
||||
useEffect(() => {
|
||||
if(username) {
|
||||
_fetchUser();
|
||||
_fetchExtraUserData();
|
||||
} else {
|
||||
setUser(null);
|
||||
}
|
||||
}, [username])
|
||||
|
||||
|
||||
//NETWORK CALLS
|
||||
const _fetchUser = async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
const _user = await getUser(username, isOwnProfile);
|
||||
setUser(_user)
|
||||
} catch (error) {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const _fetchExtraUserData = async () => {
|
||||
try {
|
||||
if (username) {
|
||||
let _isFollowing;
|
||||
let _isMuted;
|
||||
let _isFavourite;
|
||||
let follows;
|
||||
|
||||
if (!isOwnProfile) {
|
||||
const res = await getRelationship(currentAccountName, username);
|
||||
_isFollowing = res && res.follows;
|
||||
_isMuted = res && res.ignores;
|
||||
_isFavourite = await checkFavorite(username);
|
||||
}
|
||||
|
||||
try {
|
||||
follows = await getFollows(username);
|
||||
} catch (err) {
|
||||
follows = null;
|
||||
}
|
||||
|
||||
|
||||
setFollows(follows);
|
||||
setIsFollowing(_isFollowing);
|
||||
setIsMuted(_isMuted)
|
||||
setIsFavourite(_isFavourite)
|
||||
setIsLoading(false);
|
||||
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Failed to fetch complete profile data', error);
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'alert.fail',
|
||||
}),
|
||||
error.message || error.toString(),
|
||||
);
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const _onFollowPress = async () => {
|
||||
try{
|
||||
const follower = currentAccountName
|
||||
const following = username;
|
||||
|
||||
setIsLoading(true);
|
||||
await followUser(currentAccount, pinCode, {
|
||||
follower,
|
||||
following,
|
||||
})
|
||||
|
||||
setIsLoading(false);
|
||||
setIsFollowing(true)
|
||||
dispatch(
|
||||
toastNotification(
|
||||
intl.formatMessage({
|
||||
id: isFollowing ? 'alert.success_unfollow' : 'alert.success_follow',
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
catch(err){
|
||||
setIsLoading(false);
|
||||
console.warn("Failed to follow user", err)
|
||||
Bugsnag.notify(err);
|
||||
Alert.alert(intl.formatMessage({id:'alert.fail'}), err.message)
|
||||
}
|
||||
}
|
||||
|
||||
const _onFavouritePress = async () => {
|
||||
try{
|
||||
setIsLoading(true);
|
||||
let favoriteAction;
|
||||
|
||||
if (isFavourite) {
|
||||
favoriteAction = deleteFavorite;
|
||||
} else {
|
||||
favoriteAction = addFavorite;
|
||||
}
|
||||
|
||||
await favoriteAction(username)
|
||||
|
||||
dispatch(
|
||||
toastNotification(
|
||||
intl.formatMessage({
|
||||
id: isFavourite ? 'alert.success_unfavorite' : 'alert.success_favorite',
|
||||
}),
|
||||
),
|
||||
);
|
||||
setIsFavourite(!isFavourite);
|
||||
setIsLoading(false);
|
||||
}
|
||||
|
||||
catch(error){
|
||||
console.warn('Failed to perform favorite action');
|
||||
setIsLoading(false);
|
||||
Alert.alert(
|
||||
intl.formatMessage({
|
||||
id: 'alert.fail',
|
||||
}),
|
||||
error.message || error.toString(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//UI CALLBACKS
|
||||
|
||||
const _openFullProfile = () => {
|
||||
let params = {
|
||||
username,
|
||||
reputation: user ? user.reputation : null
|
||||
};
|
||||
|
||||
if (isOwnProfile) {
|
||||
navigation.navigate(ROUTES.TABBAR.PROFILE);
|
||||
} else {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.PROFILE,
|
||||
params,
|
||||
key: username,
|
||||
});
|
||||
}
|
||||
if(onClose){
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
|
||||
//extract prop values
|
||||
let _votingPower = '';
|
||||
let _resourceCredits = '';
|
||||
let _followerCount = 0;
|
||||
let _followingCount = 0;
|
||||
let _postCount = 0;
|
||||
let _avatarUrl = '';
|
||||
let _about = '';
|
||||
let _reputation = 0;
|
||||
let _createdData = null;
|
||||
|
||||
if (user && follows) {
|
||||
_votingPower = getVotingPower(user).toFixed(1);
|
||||
_resourceCredits = getRcPower(user).toFixed(0);
|
||||
_postCount = user.post_count || 0;
|
||||
_avatarUrl = user.avatar || '';
|
||||
_about = user.about?.profile?.about || '';
|
||||
_reputation = parseReputation(user.reputation);
|
||||
_createdData = getTimeFromNowNative(user.created)
|
||||
|
||||
if(follows){
|
||||
_followerCount = follows.follower_count || 0;
|
||||
_followingCount = follows.following_count || 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
const statsData1 = [
|
||||
{label:'Follower', value:_followerCount},
|
||||
{label:'Following', value:_followingCount},
|
||||
{label:'Posts', value:_postCount},
|
||||
] as StatsData[]
|
||||
|
||||
const statsData2 = [
|
||||
{label:'Resource Credits', value:_resourceCredits, suffix:'%'},
|
||||
{label:'Reputation', value:_reputation},
|
||||
] as StatsData[]
|
||||
|
||||
return (
|
||||
<View style={styles.modalStyle}>
|
||||
<ProfileBasic
|
||||
username={username}
|
||||
about={_about}
|
||||
avatarUrl={_avatarUrl}
|
||||
created={_createdData}
|
||||
votingPower={_votingPower}
|
||||
isLoading={isLoading}
|
||||
onPress={_openFullProfile}
|
||||
/>
|
||||
<ProfileStats
|
||||
data={statsData1}
|
||||
/>
|
||||
<ProfileStats
|
||||
horizontalMargin={16}
|
||||
data={statsData2}
|
||||
/>
|
||||
<MainButton
|
||||
style={styles.button}
|
||||
text='VIEW FULL PROFILE'
|
||||
onPress={_openFullProfile}
|
||||
/>
|
||||
{isLoggedIn && (
|
||||
<ActionPanel
|
||||
isFollowing={isFollowing}
|
||||
isFavourite={isFavourite}
|
||||
onFavouritePress={_onFavouritePress}
|
||||
onFollowPress={_onFollowPress}
|
||||
/>
|
||||
)}
|
||||
|
||||
</View>
|
||||
)
|
||||
};
|
@ -0,0 +1,109 @@
|
||||
import { TextStyle, ViewStyle, ImageStyle } from 'react-native';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import { getBottomSpace } from 'react-native-iphone-x-helper';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
modalStyle: {
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
margin:0,
|
||||
paddingTop:32,
|
||||
paddingBottom: getBottomSpace() + 8,
|
||||
marginHorizontal:24,
|
||||
},
|
||||
|
||||
sheetContent: {
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
position:'absolute',
|
||||
bottom:0,
|
||||
left:0,
|
||||
right:0,
|
||||
zIndex:999
|
||||
},
|
||||
|
||||
container:{
|
||||
alignItems:'center',
|
||||
marginHorizontal:16
|
||||
} as ViewStyle,
|
||||
|
||||
image:{
|
||||
width:128,
|
||||
height:128,
|
||||
borderRadius:64,
|
||||
backgroundColor: '$primaryGray'
|
||||
} as ImageStyle,
|
||||
|
||||
textContainer:{
|
||||
marginTop:32,
|
||||
marginBottom:44,
|
||||
} as ViewStyle,
|
||||
|
||||
title: {
|
||||
color: '$primaryBlack',
|
||||
alignSelf: 'center',
|
||||
textAlign: 'center',
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
marginTop:32,
|
||||
} as TextStyle,
|
||||
|
||||
statValue: {
|
||||
fontFamily:'$editorFont',
|
||||
color: '$primaryBlack',
|
||||
alignSelf: 'center',
|
||||
textAlign: 'center',
|
||||
fontSize: 34,
|
||||
fontWeight: 'normal',
|
||||
} as TextStyle,
|
||||
|
||||
statLabel: {
|
||||
color: '$primaryBlack',
|
||||
alignSelf: 'center',
|
||||
textAlign: 'center',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
} as TextStyle,
|
||||
|
||||
|
||||
bodyText: {
|
||||
color: '$primaryBlack',
|
||||
alignSelf: 'center',
|
||||
textAlign: 'center',
|
||||
fontSize: 18,
|
||||
fontWeight: '500',
|
||||
marginTop:6,
|
||||
} as TextStyle,
|
||||
|
||||
btnText:{
|
||||
color:'$pureWhite'
|
||||
} as TextStyle,
|
||||
|
||||
button:{
|
||||
marginTop: 40,
|
||||
backgroundColor:'$primaryBlue',
|
||||
paddingHorizontal:44,
|
||||
paddingVertical:16,
|
||||
borderRadius:32,
|
||||
justifyContent:'center',
|
||||
alignItems:'center'
|
||||
} as ViewStyle,
|
||||
|
||||
|
||||
actionPanel:{
|
||||
position: 'absolute',
|
||||
right:0,
|
||||
top:0,
|
||||
flexDirection:'row',
|
||||
alignItems:'center',
|
||||
} as ViewStyle,
|
||||
|
||||
progressCircle:{
|
||||
position:'absolute',
|
||||
top:0,
|
||||
bottom:0,
|
||||
left:0,
|
||||
right:0,
|
||||
alignItems:'center',
|
||||
justifyContent:'center'
|
||||
} as ViewStyle
|
||||
|
||||
})
|
@ -0,0 +1,54 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { AlertButton } from 'react-native';
|
||||
import { Source } from 'react-native-fast-image';
|
||||
import ActionSheet from 'react-native-actions-sheet';
|
||||
import { QuickProfileContent } from '../children/quickProfileContent';
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
import styles from '../children/quickProfileStyles';
|
||||
import { useAppDispatch, useAppSelector } from '../../../../hooks';
|
||||
import { hideProfileModal } from '../../../../redux/actions/uiAction';
|
||||
|
||||
|
||||
|
||||
export interface ActionModalData {
|
||||
navigation:any
|
||||
}
|
||||
|
||||
|
||||
export const QuickProfileModal = ({navigation}) => {
|
||||
const sheetModalRef = useRef<ActionSheet>();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const profileModalUsername = useAppSelector((state)=>state.ui.profileModalUsername);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if(profileModalUsername){
|
||||
sheetModalRef.current.show();
|
||||
}else {
|
||||
sheetModalRef.current.hide();
|
||||
}
|
||||
}, [profileModalUsername])
|
||||
|
||||
|
||||
const _onClose = () => {
|
||||
dispatch(hideProfileModal());
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<ActionSheet
|
||||
ref={sheetModalRef}
|
||||
gestureEnabled={true}
|
||||
containerStyle={styles.sheetContent}
|
||||
onClose={_onClose}
|
||||
indicatorColor={EStyleSheet.value('$primaryWhiteLightBackground')}>
|
||||
|
||||
<QuickProfileContent
|
||||
navigation={navigation}
|
||||
username={profileModalUsername}
|
||||
onClose={_onClose}
|
||||
/>
|
||||
</ActionSheet>
|
||||
);
|
||||
};
|
1
src/components/organisms/quickProfileModal/index.ts
Normal file
1
src/components/organisms/quickProfileModal/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './container/quickProfileModal';
|
@ -4,16 +4,15 @@ import { connect } from 'react-redux';
|
||||
import get from 'lodash/get';
|
||||
|
||||
// Services
|
||||
import { act } from 'react-test-renderer';
|
||||
import { getPost, getActiveVotes } from '../../../providers/hive/dhive';
|
||||
import { getPost } from '../../../providers/hive/dhive';
|
||||
import { getPostReblogs } from '../../../providers/ecency/ecency';
|
||||
|
||||
import { parseActiveVotes } from '../../../utils/postParser';
|
||||
|
||||
import PostCardView from '../view/postCardView';
|
||||
|
||||
// Constants
|
||||
import { default as ROUTES } from '../../../constants/routeNames';
|
||||
import { useAppDispatch } from '../../../hooks';
|
||||
import { showProfileModal } from '../../../redux/actions/uiAction';
|
||||
/*
|
||||
* Props Name Description Value
|
||||
*@props --> props name here description here Value Type Here
|
||||
@ -31,6 +30,8 @@ const PostCardContainer = ({
|
||||
setImageHeight,
|
||||
pageType,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [_content, setContent] = useState(content);
|
||||
const [reblogs, setReblogs] = useState([]);
|
||||
const activeVotes = get(_content, 'active_votes', []);
|
||||
@ -78,23 +79,8 @@ const PostCardContainer = ({
|
||||
|
||||
const _handleOnUserPress = (username) => {
|
||||
if (_content) {
|
||||
let params = {
|
||||
username: username || get(_content, 'author'),
|
||||
reputation: !username && get(_content, 'author_reputation'),
|
||||
};
|
||||
|
||||
if (
|
||||
get(currentAccount, 'name') === params.username &&
|
||||
(pageType === 'main' || pageType === 'ownProfile')
|
||||
) {
|
||||
navigation.navigate(ROUTES.TABBAR.PROFILE);
|
||||
} else {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.PROFILE,
|
||||
params,
|
||||
key: get(_content, 'author'),
|
||||
});
|
||||
}
|
||||
username = username || get(_content, 'author');
|
||||
dispatch(showProfileModal(username));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { View, Text, TouchableOpacity } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
import { injectIntl } from 'react-intl';
|
||||
|
||||
@ -12,6 +13,7 @@ import styles from './postHeaderDescriptionStyles';
|
||||
|
||||
import { default as ROUTES } from '../../../../constants/routeNames';
|
||||
import { IconButton } from '../../..';
|
||||
import { showProfileModal } from '../../../../redux/actions/uiAction';
|
||||
|
||||
// Constants
|
||||
const DEFAULT_IMAGE = require('../../../../assets/ecency.png');
|
||||
@ -21,19 +23,12 @@ class PostHeaderDescription extends PureComponent {
|
||||
|
||||
// Component Functions
|
||||
_handleOnUserPress = (username) => {
|
||||
const { navigation, profileOnPress, reputation } = this.props;
|
||||
const { profileOnPress, dispatch } = this.props;
|
||||
|
||||
if (profileOnPress) {
|
||||
profileOnPress(username);
|
||||
} else {
|
||||
navigation.navigate({
|
||||
routeName: ROUTES.SCREENS.PROFILE,
|
||||
params: {
|
||||
username,
|
||||
reputation,
|
||||
},
|
||||
key: username,
|
||||
});
|
||||
dispatch(showProfileModal(username));
|
||||
}
|
||||
};
|
||||
|
||||
@ -181,4 +176,6 @@ class PostHeaderDescription extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
export default withNavigation(injectIntl(PostHeaderDescription));
|
||||
const mapStateToProps = () => ({});
|
||||
|
||||
export default connect(mapStateToProps)(withNavigation(injectIntl(PostHeaderDescription)));
|
||||
|
@ -174,6 +174,7 @@
|
||||
"day": "day",
|
||||
"hive_dollars": "Hive Dollars",
|
||||
"savings": "Savings",
|
||||
"joined": "Joined {time} ago",
|
||||
"edit": {
|
||||
"display_name": "Display Name",
|
||||
"about": "About",
|
||||
@ -672,5 +673,14 @@
|
||||
"line3_heading":"Join Ecency communities!",
|
||||
"line3_body":"Build community you own, get rewarded and reward others.",
|
||||
"get_started":"Get started!"
|
||||
},
|
||||
"time":{
|
||||
"second":"seconds",
|
||||
"minute":"minutes",
|
||||
"hour":"hours",
|
||||
"week":"weeks",
|
||||
"day":"days",
|
||||
"month":"months",
|
||||
"year":"years"
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import {
|
||||
SHOW_ACTION_MODAL,
|
||||
HIDE_ACTION_MODAL,
|
||||
SET_AVATAR_CACHE_STAMP,
|
||||
SHOW_PROFILE_MODAL,
|
||||
HIDE_PROFILE_MODAL
|
||||
} from '../constants/constants';
|
||||
|
||||
export const updateActiveBottomTab = (payload:string) => ({
|
||||
@ -35,10 +37,24 @@ export const showActionModal = (title:string, body?:string, buttons?:AlertButton
|
||||
type: SHOW_ACTION_MODAL,
|
||||
});
|
||||
|
||||
|
||||
|
||||
export const hideActionModal = () => ({
|
||||
type: HIDE_ACTION_MODAL,
|
||||
});
|
||||
|
||||
|
||||
export const showProfileModal = (username:string) => ({
|
||||
payload: {
|
||||
profileModalUsername: username
|
||||
},
|
||||
type: SHOW_PROFILE_MODAL,
|
||||
});
|
||||
|
||||
export const hideProfileModal = () => ({
|
||||
type: HIDE_PROFILE_MODAL,
|
||||
});
|
||||
|
||||
export const setRcOffer = (payload:boolean) => ({
|
||||
payload,
|
||||
type: RC_OFFER,
|
||||
|
@ -55,6 +55,8 @@ export const TOGGLE_ACCOUNTS_BOTTOM_SHEET = 'TOGGLE_ACCOUNTS_BOTTOM_SHEET';
|
||||
export const SHOW_ACTION_MODAL = 'SHOW_ACTION_MODAL';
|
||||
export const HIDE_ACTION_MODAL = 'HIDE_ACTION_MODAL';
|
||||
export const SET_AVATAR_CACHE_STAMP = 'SET_AVATAR_CACHE_STAMP';
|
||||
export const SHOW_PROFILE_MODAL = 'SHOW_PROFILE_MODAL';
|
||||
export const HIDE_PROFILE_MODAL = 'HIDE_PROFILE_MODAL';
|
||||
|
||||
// POSTS
|
||||
export const SET_FEED_POSTS = 'SET_FEED_POSTS';
|
||||
|
@ -7,6 +7,8 @@ import {
|
||||
SHOW_ACTION_MODAL,
|
||||
HIDE_ACTION_MODAL,
|
||||
SET_AVATAR_CACHE_STAMP,
|
||||
SHOW_PROFILE_MODAL,
|
||||
HIDE_PROFILE_MODAL,
|
||||
} from '../constants/constants';
|
||||
|
||||
interface UiState {
|
||||
@ -17,7 +19,8 @@ interface UiState {
|
||||
isVisibleAccountsBottomSheet:boolean;
|
||||
actionModalVisible:boolean;
|
||||
actionModalData:any;
|
||||
avatarCacheStamp:number
|
||||
avatarCacheStamp:number;
|
||||
profileModalUsername:string;
|
||||
}
|
||||
|
||||
const initialState:UiState = {
|
||||
@ -28,7 +31,8 @@ const initialState:UiState = {
|
||||
isVisibleAccountsBottomSheet: false,
|
||||
actionModalVisible: false,
|
||||
actionModalData: null,
|
||||
avatarCacheStamp: 0
|
||||
avatarCacheStamp: 0,
|
||||
profileModalUsername: ''
|
||||
};
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
@ -61,6 +65,20 @@ export default function (state = initialState, action) {
|
||||
};
|
||||
}
|
||||
|
||||
case SHOW_PROFILE_MODAL: {
|
||||
return {
|
||||
...state,
|
||||
profileModalUsername: action.payload.profileModalUsername,
|
||||
};
|
||||
}
|
||||
|
||||
case HIDE_PROFILE_MODAL: {
|
||||
return {
|
||||
...state,
|
||||
profileModalUsername: '',
|
||||
};
|
||||
}
|
||||
|
||||
case RC_OFFER:
|
||||
return {
|
||||
...state,
|
||||
|
@ -87,6 +87,7 @@ import {
|
||||
} from '../../../redux/actions/applicationActions';
|
||||
import {
|
||||
hideActionModal,
|
||||
hideProfileModal,
|
||||
setAvatarCacheStamp,
|
||||
setRcOffer,
|
||||
showActionModal,
|
||||
@ -761,6 +762,7 @@ class ApplicationContainer extends Component {
|
||||
|
||||
//reset certain properties
|
||||
dispatch(hideActionModal());
|
||||
dispatch(hideProfileModal());
|
||||
dispatch(toastNotification(''));
|
||||
dispatch(resetLocalVoteMap());
|
||||
dispatch(setRcOffer(false));
|
||||
|
@ -25,6 +25,7 @@ import {
|
||||
AccountsBottomSheet,
|
||||
ActionModal,
|
||||
ForegroundNotification,
|
||||
QuickProfileModal,
|
||||
} from '../../../components';
|
||||
|
||||
// Themes (Styles)
|
||||
@ -113,6 +114,7 @@ class ApplicationScreen extends Component {
|
||||
toastNotification,
|
||||
isReady,
|
||||
foregroundNotificationData,
|
||||
navigation,
|
||||
} = this.props;
|
||||
const { isShowToastNotification, showWelcomeModal } = this.state;
|
||||
const barStyle = isDarkTheme ? 'light-content' : 'dark-content';
|
||||
@ -171,6 +173,7 @@ class ApplicationScreen extends Component {
|
||||
<ForegroundNotification remoteMessage={foregroundNotificationData} />
|
||||
<AccountsBottomSheet />
|
||||
<ActionModal />
|
||||
<QuickProfileModal navigation={{ navigate }} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import ROUTES from '../../../constants/routeNames';
|
||||
|
||||
// Components
|
||||
import NotificationScreen from '../screen/notificationScreen';
|
||||
import { showProfileModal } from '../../../redux/actions/uiAction';
|
||||
|
||||
class NotificationContainer extends Component {
|
||||
constructor(props) {
|
||||
@ -118,6 +119,11 @@ class NotificationContainer extends Component {
|
||||
}
|
||||
};
|
||||
|
||||
_handleOnUserPress = (username) => {
|
||||
const { dispatch } = this.props;
|
||||
dispatch(showProfileModal(username));
|
||||
};
|
||||
|
||||
_readAllNotification = () => {
|
||||
const { dispatch, intl, isConnected } = this.props;
|
||||
const { notifications } = this.state;
|
||||
@ -174,6 +180,7 @@ class NotificationContainer extends Component {
|
||||
getActivities={this._getActivities}
|
||||
notifications={notifications}
|
||||
navigateToNotificationRoute={this._navigateToNotificationRoute}
|
||||
handleOnUserPress={this._handleOnUserPress}
|
||||
readAllNotification={this._readAllNotification}
|
||||
handleLoginPress={this._handleOnPressLogin}
|
||||
isNotificationRefreshing={isRefreshing}
|
||||
|
@ -16,6 +16,7 @@ const NotificationScreen = ({
|
||||
getActivities,
|
||||
intl,
|
||||
navigateToNotificationRoute,
|
||||
handleOnUserPress,
|
||||
readAllNotification,
|
||||
isNotificationRefreshing,
|
||||
changeSelectedFilter,
|
||||
@ -42,6 +43,7 @@ const NotificationScreen = ({
|
||||
getActivities={getActivities}
|
||||
notifications={notifications}
|
||||
navigateToNotificationRoute={navigateToNotificationRoute}
|
||||
handleOnUserPress={handleOnUserPress}
|
||||
readAllNotification={readAllNotification}
|
||||
isNotificationRefreshing={isNotificationRefreshing}
|
||||
changeSelectedFilter={changeSelectedFilter}
|
||||
|
29
yarn.lock
29
yarn.lock
@ -3513,7 +3513,7 @@ css-mediaquery@^0.1.2:
|
||||
resolved "https://registry.yarnpkg.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz#6a2c37344928618631c54bd33cedd301da18bea0"
|
||||
integrity sha1-aiw3NEkoYYYxxUvTPO3TAdoYvqA=
|
||||
|
||||
css-select@^2.0.2:
|
||||
css-select@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef"
|
||||
integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==
|
||||
@ -3532,10 +3532,10 @@ css-to-react-native@^3.0.0:
|
||||
css-color-keywords "^1.0.0"
|
||||
postcss-value-parser "^4.0.2"
|
||||
|
||||
css-tree@^1.0.0-alpha.37:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.2.tgz#9ae393b5dafd7dae8a622475caec78d3d8fbd7b5"
|
||||
integrity sha512-wCoWush5Aeo48GLhfHPbmvZs59Z+M7k5+B1xDnXbdWNcEF423DoFdqSWE0PM5aNk5nI5cp1q7ms36zGApY/sKQ==
|
||||
css-tree@^1.0.0-alpha.39:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
|
||||
integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
|
||||
dependencies:
|
||||
mdn-data "2.0.14"
|
||||
source-map "^0.6.1"
|
||||
@ -8877,6 +8877,13 @@ react-native-os@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/react-native-os/-/react-native-os-1.2.6.tgz#1bb16d78ccad1143972183a04f443cf1af9fbefa"
|
||||
integrity sha512-OlT+xQAcvkcnf7imgXiu+myMkqDt4xw2bP5SlVo19hEn5XHBkPMLX7dk3sSGxxncH/ToMDsf1KLyrPabNVtadA==
|
||||
|
||||
react-native-progress@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-progress/-/react-native-progress-5.0.0.tgz#f5ac6ceaeee27f184c660b00f29419e82a9d0ab0"
|
||||
integrity sha512-KjnGIt3r9i5Kn2biOD9fXLJocf0bwxPRxOyAgXEnZTJQU2O+HyzgGFRCbM5h3izm9kKIkSc1txh8aGmMafCD9A==
|
||||
dependencies:
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-native-push-notification@^7.3.1:
|
||||
version "7.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-push-notification/-/react-native-push-notification-7.3.1.tgz#1495feacd25169b998446dcf7b448a197ae5dca0"
|
||||
@ -8975,13 +8982,13 @@ react-native-splash-screen@^3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/react-native-splash-screen/-/react-native-splash-screen-3.2.0.tgz#d47ec8557b1ba988ee3ea98d01463081b60fff45"
|
||||
integrity sha512-Ls9qiNZzW/OLFoI25wfjjAcrf2DZ975hn2vr6U9gyuxi2nooVbzQeFoQS5vQcbCt9QX5NY8ASEEAtlLdIa6KVg==
|
||||
|
||||
react-native-svg@^9.5.3:
|
||||
version "9.13.6"
|
||||
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-9.13.6.tgz#5365fba2bc460054b90851e71f2a71006a5d373f"
|
||||
integrity sha512-vjjuJhEhQCwWjqsgWyGy6/C/LIBM2REDxB40FU1PMhi8T3zQUwUHnA6M15pJKlQG8vaZyA+QnLyIVhjtujRgig==
|
||||
react-native-svg@^12.1.1:
|
||||
version "12.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-native-svg/-/react-native-svg-12.1.1.tgz#5f292410b8bcc07bbc52b2da7ceb22caf5bcaaee"
|
||||
integrity sha512-NIAJ8jCnXGCqGWXkkJ1GTzO4a3Md5at5sagYV8Vh4MXYnL4z5Rh428Wahjhh+LIjx40EE5xM5YtwyJBqOIba2Q==
|
||||
dependencies:
|
||||
css-select "^2.0.2"
|
||||
css-tree "^1.0.0-alpha.37"
|
||||
css-select "^2.1.0"
|
||||
css-tree "^1.0.0-alpha.39"
|
||||
|
||||
react-native-swiper@^1.6.0-rc.3:
|
||||
version "1.6.0"
|
||||
|
Loading…
Reference in New Issue
Block a user