Merge branch 'master' of https://github.com/esteemapp/esteem-mobile into markdownToHtml

This commit is contained in:
u-e 2018-12-27 15:17:17 +03:00
commit 4562771a83
34 changed files with 697 additions and 580 deletions

View File

@ -5,3 +5,4 @@ OLD_IMAGE_API=
SEARCH_API_TOKEN= SEARCH_API_TOKEN=
SEARCH_API_URL= SEARCH_API_URL=
SERVER_LIST_API= SERVER_LIST_API=
PIN_KEY=

View File

@ -2,6 +2,8 @@
printf "post-clone.sh\n" printf "post-clone.sh\n"
node -v
# please specify required Node.js version # please specify required Node.js version
NODE_VERSION=8.12.0 NODE_VERSION=8.12.0
@ -10,3 +12,7 @@ npm config delete prefix
. ~/.bashrc . ~/.bashrc
nvm install "$NODE_VERSION" nvm install "$NODE_VERSION"
nvm alias node8 "$NODE_VERSION" nvm alias node8 "$NODE_VERSION"
nvm alias default v8.12.0
node -v
printf "end of post-clone.sh\n"

View File

@ -3,7 +3,7 @@
printf "Old .env file:\n" printf "Old .env file:\n"
cat .env cat .env
printf "Started script:\n" printf "Started script:\n"
ENV_WHITELIST=${ENV_WHITELIST:-"/ACTIVITY|WEBSOCKET|BACKEND|API|TOKEN|URL/"} ENV_WHITELIST=${ENV_WHITELIST:-"/ACTIVITY|WEBSOCKET|BACKEND|API|TOKEN|PIN|URL/"}
printf "Creating an .env file with the following whitelist:\n" printf "Creating an .env file with the following whitelist:\n"
printf "%s\n\n" $ENV_WHITELIST printf "%s\n\n" $ENV_WHITELIST
set | egrep -e $ENV_WHITELIST | egrep -v "^_" | egrep -v "WHITELIST" | egrep -v "USER-DEFINED" > .env set | egrep -e $ENV_WHITELIST | egrep -v "^_" | egrep -v "WHITELIST" | egrep -v "USER-DEFINED" > .env

View File

@ -4,19 +4,27 @@ import { Icon } from '../../../icon';
import styles from './textWithIconStyles'; import styles from './textWithIconStyles';
const TextWithIcon = ({ const TextWithIcon = ({
iconName, text, isClickable, onPress, iconStyle, iconType, iconName, text, isClickable, onPress, iconStyle, iconType, iconSize,
}) => ( }) => (
<View style={styles.container}> <View style={styles.container}>
{isClickable || onPress ? ( {isClickable || onPress ? (
<TouchableHighlight underlayColor="transparent" onPress={() => onPress && onPress()}> <TouchableHighlight underlayColor="transparent" onPress={() => onPress && onPress()}>
<View style={styles.wrapper}> <View style={styles.wrapper}>
<Icon style={[styles.icon, iconStyle]} name={iconName} iconType={iconType} /> <Icon
style={[styles.icon, iconStyle, iconSize && { fontSize: iconSize }]}
name={iconName}
iconType={iconType}
/>
<Text style={[styles.text]}>{text}</Text> <Text style={[styles.text]}>{text}</Text>
</View> </View>
</TouchableHighlight> </TouchableHighlight>
) : ( ) : (
<View style={styles.wrapper}> <View style={styles.wrapper}>
<Icon style={[styles.icon, iconStyle]} name={iconName} iconType={iconType} /> <Icon
style={[styles.icon, iconStyle, iconSize && { fontSize: iconSize }]}
name={iconName}
iconType={iconType}
/>
<Text style={styles.text}>{text}</Text> <Text style={styles.text}>{text}</Text>
</View> </View>
)} )}

View File

@ -54,7 +54,7 @@ const WalletLineItem = ({
</Text> </Text>
</View> </View>
)} )}
{description && ( {!!description && (
<Text style={[styles.description, !iconName && styles.onlyText]}>{description}</Text> <Text style={[styles.description, !iconName && styles.onlyText]}>{description}</Text>
)} )}
</View> </View>

View File

@ -57,9 +57,9 @@ class CollapsibleCardView extends PureComponent {
_getMinValue = () => 0; _getMinValue = () => 0;
_toggleOnPress = () => { _toggleOnPress = () => {
const { handleOnExpanded } = this.props; const { handleOnExpanded, moreHeight } = this.props;
Animated.timing(this.anime.height, { Animated.timing(this.anime.height, {
toValue: this.anime.expanded ? this._getMinValue() : this._getMaxValue(), toValue: this.anime.expanded ? this._getMinValue() : this._getMaxValue() + moreHeight,
duration: 200, duration: 200,
}).start(); }).start();
this.anime.expanded = !this.anime.expanded; this.anime.expanded = !this.anime.expanded;

View File

@ -9,7 +9,6 @@ export default EStyleSheet.create({
backgroundColor: '$primaryBlue', backgroundColor: '$primaryBlue',
}, },
input: { input: {
alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
height: 18, height: 18,
margin: 10, margin: 10,

View File

@ -1,5 +1,5 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Animated } from 'react-native'; import { Animated, Easing, View } from 'react-native';
// Styles // Styles
import styles from './pinAnimatedInputStyles'; import styles from './pinAnimatedInputStyles';
@ -13,38 +13,73 @@ class PinAnimatedInput extends PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = {}; this.state = {};
this.dots = [];
this.dots[0] = new Animated.Value(0);
this.dots[1] = new Animated.Value(0);
this.dots[2] = new Animated.Value(0);
this.dots[3] = new Animated.Value(0);
} }
componentWillReceiveProps(nextProps) {
const { loading } = this.props;
if (loading !== nextProps.loading) {
if (nextProps.loading) {
this._startLoadingAnimation();
} else {
this._stopLoadingAnimation();
}
}
}
_startLoadingAnimation = () => {
const { loading } = this.props;
[...Array(4)].map((item, index) => {
this.dots[index].setValue(0);
});
Animated.sequence([
...this.dots.map(item => Animated.timing(item, {
toValue: 1,
duration: 250,
easing: Easing.linear,
})),
]).start(() => {
if (loading) this._startLoadingAnimation();
});
};
_stopLoadingAnimation = () => {
[...Array(4)].map((item, index) => {
this.dots[index].stopAnimation();
});
};
render() { render() {
const { pin } = this.props; const { pin } = this.props;
const test = new Animated.Value(0); const marginBottom = [];
const tilt = test.interpolate({
inputRange: [0, 0.3, 0.6, 0.9], [...Array(4)].map((item, index) => {
outputRange: [0, -50, 50, 0], marginBottom[index] = this.dots[index].interpolate({
inputRange: [0, 0.5, 1],
outputRange: [0, 20, 0],
}); });
});
return ( return (
<Animated.View <View style={[styles.container]}>
style={[ {this.dots.map((val, index) => {
{
transform: [{ translateX: tilt }],
},
styles.container,
]}
>
{[...Array(4)].map((val, index) => {
if (pin.length > index) { if (pin.length > index) {
return ( return (
<Animated.View key={`passwordItem-${index}`} style={styles.input}>
<Animated.View <Animated.View
key={`passwordItem-${index}`} key={`passwordItem-${index}`}
style={[styles.input, styles.inputWithBackground]} style={[styles.input, styles.inputWithBackground, { bottom: marginBottom[index] }]}
/> />
</Animated.View>
); );
} }
return <Animated.View key={`passwordItem-${index}`} style={styles.input} />; return <View key={`passwordItem-${index}`} style={styles.input} />;
})} })}
</Animated.View> </View>
); );
} }
} }

View File

@ -5,6 +5,9 @@ import { PostHeaderDescription } from '../../postElements';
import { PostDropdown } from '../../postDropdown'; import { PostDropdown } from '../../postDropdown';
import { Icon } from '../../icon'; import { Icon } from '../../icon';
// Utils
import { makeCountFriendly } from '../../../utils/formatter';
// STEEM // STEEM
import { Upvote } from '../../upvote'; import { Upvote } from '../../upvote';
// Styles // Styles
@ -59,6 +62,9 @@ class PostCard extends Component {
const _image = content && content.image const _image = content && content.image
? { uri: content.image, priority: FastImage.priority.high } ? { uri: content.image, priority: FastImage.priority.high }
: DEFAULT_IMAGE; : DEFAULT_IMAGE;
const reblogedBy = content.reblogged_by && content.reblogged_by[0];
// repeat icon
// text rebloged by ${reblogedBy}
return ( return (
<View style={styles.post}> <View style={styles.post}>
@ -72,6 +78,7 @@ class PostCard extends Component {
reputation={content.author_reputation} reputation={content.author_reputation}
size={32} size={32}
tag={content.category} tag={content.category}
reblogedBy={reblogedBy}
/> />
<View style={styles.dropdownWrapper}> <View style={styles.dropdownWrapper}>
<PostDropdown content={content} /> <PostDropdown content={content} />
@ -103,12 +110,12 @@ class PostCard extends Component {
iconType="MaterialIcons" iconType="MaterialIcons"
name="people" name="people"
/> />
<Text style={styles.comment}>{content.vote_count}</Text> <Text style={styles.comment}>{makeCountFriendly(content.vote_count)}</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<TouchableOpacity style={styles.commentButton}> <TouchableOpacity style={styles.commentButton}>
<Icon style={[styles.commentIcon]} iconType="MaterialIcons" name="comment" /> <Icon style={[styles.commentIcon]} iconType="MaterialIcons" name="comment" />
<Text style={styles.comment}>{content.children}</Text> <Text style={styles.comment}>{makeCountFriendly(content.children)}</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
</View> </View>

View File

@ -55,10 +55,12 @@ class PostDropdownContainer extends PureComponent {
}; };
_reblog = () => { _reblog = () => {
const { currentAccount, content, isLoggedIn } = this.props; const {
currentAccount, content, isLoggedIn, pinCode,
} = this.props;
if (isLoggedIn) { if (isLoggedIn) {
reblog(currentAccount, content.author, content.permlink) reblog(currentAccount, pinCode, content.author, content.permlink)
.then((result) => { .then(() => {
Alert.alert('Success', 'Rebloged!'); Alert.alert('Success', 'Rebloged!');
}) })
.catch((error) => { .catch((error) => {
@ -98,5 +100,6 @@ class PostDropdownContainer extends PureComponent {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
isLoggedIn: state.application.isLoggedIn, isLoggedIn: state.application.isLoggedIn,
currentAccount: state.account.currentAccount, currentAccount: state.account.currentAccount,
pinCode: state.account.pin,
}); });
export default withNavigation(connect(mapStateToProps)(PostDropdownContainer)); export default withNavigation(connect(mapStateToProps)(PostDropdownContainer));

View File

@ -5,7 +5,7 @@ import { withNavigation } from 'react-navigation';
import FastImage from 'react-native-fast-image'; import FastImage from 'react-native-fast-image';
// Components // Components
import { Tag } from '../../../basicUIElements'; import { Tag, TextWithIcon } from '../../../basicUIElements';
// Styles // Styles
import styles from './postHeaderDescriptionStyles'; import styles from './postHeaderDescriptionStyles';
@ -43,7 +43,15 @@ class PostHeaderDescription extends PureComponent {
render() { render() {
const { const {
date, avatar, name, reputation, size, tag, tagOnPress, isHideImage, avatar,
date,
isHideImage,
name,
reblogedBy,
reputation,
size,
tag,
tagOnPress,
} = this.props; } = this.props;
const _reputationText = `(${reputation})`; const _reputationText = `(${reputation})`;
@ -77,6 +85,7 @@ class PostHeaderDescription extends PureComponent {
</TouchableOpacity> </TouchableOpacity>
)} )}
<Text style={styles.date}>{date}</Text> <Text style={styles.date}>{date}</Text>
{!!reblogedBy && <TextWithIcon text={reblogedBy} iconType="MaterialIcons" iconName="repeat" />}
</View> </View>
); );
} }

View File

@ -22,8 +22,8 @@ export default EStyleSheet.create({
width: '$deviceWidth - 24', width: '$deviceWidth - 24',
flexDirection: 'row', flexDirection: 'row',
justifyContent: 'space-between', justifyContent: 'space-between',
marginBottom: 17, marginVertical: 10,
marginTop: 10, height: 30,
}, },
leftIcons: { leftIcons: {
flexDirection: 'row', flexDirection: 'row',
@ -35,10 +35,11 @@ export default EStyleSheet.create({
justifyContent: 'flex-end', justifyContent: 'flex-end',
}, },
insetIconStyle: { insetIconStyle: {
marginRight: 12, marginRight: 20,
color: '$primaryDarkText',
}, },
activityIndicator: { activityIndicator: {
marginRight: 12, marginRight: 20,
width: 30, width: 30,
}, },
followCountWrapper: { followCountWrapper: {
@ -58,6 +59,13 @@ export default EStyleSheet.create({
}, },
// TODO: look at here // TODO: look at here
dropdownIconStyle: { dropdownIconStyle: {
marginBottom: 7, width: 25,
height: 25,
left: -5,
marginBottom: 3,
color: '#c1c5c7',
},
dropdownStyle: {
maxWidth: 150,
}, },
}); });

View File

@ -17,6 +17,10 @@ import DARK_COVER_IMAGE from '../../../assets/dark_cover_image.png';
import { TextWithIcon } from '../../basicUIElements'; import { TextWithIcon } from '../../basicUIElements';
import { PercentBar } from '../../percentBar'; import { PercentBar } from '../../percentBar';
import { IconButton } from '../../iconButton'; import { IconButton } from '../../iconButton';
import { DropdownButton } from '../../dropdownButton';
// Utils
import { makeCountFriendly } from '../../../utils/formatter';
// Styles // Styles
import styles from './profileSummaryStyles'; import styles from './profileSummaryStyles';
@ -43,6 +47,16 @@ class ProfileSummaryView extends PureComponent {
Linking.openURL(url); Linking.openURL(url);
}; };
_handleOnDropdownSelect = (index) => {
const { isMuted, handleMuteUnmuteUser } = this.props;
// This funciton should have switch case but now only has one option therefor
// temporarily I created with if statments
if (index === '0' && handleMuteUnmuteUser) {
handleMuteUnmuteUser(!isMuted);
}
};
render() { render() {
const { isShowPercentText } = this.state; const { isShowPercentText } = this.state;
const { const {
@ -51,8 +65,8 @@ class ProfileSummaryView extends PureComponent {
followerCount, followerCount,
followingCount, followingCount,
handleFollowUnfollowUser, handleFollowUnfollowUser,
handleMuteUnmuteUser,
handleOnFollowsPress, handleOnFollowsPress,
handleUIChange,
hoursRC, hoursRC,
hoursVP, hoursVP,
intl, intl,
@ -66,40 +80,43 @@ class ProfileSummaryView extends PureComponent {
location, location,
percentRC, percentRC,
percentVP, percentVP,
handleUIChange,
} = this.props; } = this.props;
const dropdownOpions = [];
const votingPowerHoursText = hoursVP && `• Full in ${hoursVP} hours`; const votingPowerHoursText = hoursVP && `• Full in ${hoursVP} hours`;
const votingPowerText = `Voting power: ${percentVP}% ${votingPowerHoursText || ''}`; const votingPowerText = `Voting power: ${percentVP}% ${votingPowerHoursText || ''}`;
const rcPowerHoursText = hoursRC && `• Full in ${hoursRC} hours`; const rcPowerHoursText = hoursRC && `• Full in ${hoursRC} hours`;
const rcPowerText = `RCs: ${percentRC}% ${rcPowerHoursText || ''}`; const rcPowerText = `RCs: ${percentRC}% ${rcPowerHoursText || ''}`;
/* eslint-disable */ const rowLength = (location ? location.length : 0) + (link ? link.length : 0) + (date ? date.length : 0);
const rowLength = location const isColumn = rowLength && DEVICE_WIDTH / rowLength <= 7.3;
? location.length
: null + link
? link.length
: null + date
? date.length
: null;
const isColumn = rowLength && DEVICE_WIDTH / rowLength <= 15; const followButtonIcon = !isFollowing ? 'account-plus' : 'account-minus';
const followButtonIcon = !isFollowing ? 'user-follow' : 'user-unfollow';
const ignoreButtonIcon = !isMuted ? 'ban' : 'minus';
const coverImageUrl = `http://img.esteem.app/400x0/${coverImage}`; const coverImageUrl = `http://img.esteem.app/400x0/${coverImage}`;
dropdownOpions.push(!isMuted ? 'MUTE' : 'UNMUTE');
return ( return (
<Fragment> <Fragment>
<View style={[isColumn ? styles.textWithIconWrapperColumn : styles.textWithIconWrapper]}> <View style={[isColumn ? styles.textWithIconWrapperColumn : styles.textWithIconWrapper]}>
{!!location && <TextWithIcon text={location} iconName="md-navigate" />} {!!location && (
<TextWithIcon
text={location}
iconName="near-me"
iconType="MaterialIcons"
iconSize={14}
/>
)}
{!!link && ( {!!link && (
<TextWithIcon <TextWithIcon
isClickable isClickable
onPress={() => this._handleOnPressLink(link)} onPress={() => this._handleOnPressLink(link)}
text={link} text={link}
iconName="md-globe" iconSize={14}
iconName="earth"
iconType="MaterialCommunityIcons"
/> />
)} )}
{!!date && <TextWithIcon text={date} iconName="md-calendar" />} {!!date && <TextWithIcon text={date} iconName="md-calendar" iconSize={14} />}
</View> </View>
<Image <Image
style={styles.longImage} style={styles.longImage}
@ -107,9 +124,8 @@ class ProfileSummaryView extends PureComponent {
defaultSource={isDarkTheme ? DARK_COVER_IMAGE : LIGHT_COVER_IMAGE} defaultSource={isDarkTheme ? DARK_COVER_IMAGE : LIGHT_COVER_IMAGE}
/> />
<TouchableOpacity <TouchableOpacity
onPress={() => onPress={() => this.setState({ isShowPercentText: !isShowPercentText }, () => {
this.setState({ isShowPercentText: !isShowPercentText }, () => { handleUIChange(!isShowPercentText ? 30 : 0);
handleUIChange(isShowPercentText ? 0 : 30);
}) })
} }
> >
@ -136,7 +152,7 @@ class ProfileSummaryView extends PureComponent {
<Fragment> <Fragment>
<TouchableOpacity onPress={() => handleOnFollowsPress(false)}> <TouchableOpacity onPress={() => handleOnFollowsPress(false)}>
<View style={styles.followCountWrapper}> <View style={styles.followCountWrapper}>
<Text style={styles.followCount}>{followerCount}</Text> <Text style={styles.followCount}>{makeCountFriendly(followerCount)}</Text>
<Text style={styles.followText}> <Text style={styles.followText}>
{' '} {' '}
{intl.formatMessage({ {intl.formatMessage({
@ -147,7 +163,7 @@ class ProfileSummaryView extends PureComponent {
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity onPress={() => handleOnFollowsPress(true)}> <TouchableOpacity onPress={() => handleOnFollowsPress(true)}>
<View style={styles.followCountWrapper}> <View style={styles.followCountWrapper}>
<Text style={styles.followCount}>{followingCount}</Text> <Text style={styles.followCount}>{makeCountFriendly(followingCount)}</Text>
<Text style={styles.followText}> <Text style={styles.followText}>
{intl.formatMessage({ {intl.formatMessage({
id: 'profile.following', id: 'profile.following',
@ -163,9 +179,9 @@ class ProfileSummaryView extends PureComponent {
<Fragment> <Fragment>
<IconButton <IconButton
backgroundColor="transparent" backgroundColor="transparent"
name="heart" name="favorite-border"
iconType="SimpleLineIcons" iconType="MaterialIcons"
size={16} size={20}
style={[styles.insetIconStyle]} style={[styles.insetIconStyle]}
color="#c1c5c7" color="#c1c5c7"
/> />
@ -175,24 +191,23 @@ class ProfileSummaryView extends PureComponent {
<IconButton <IconButton
backgroundColor="transparent" backgroundColor="transparent"
name={followButtonIcon} name={followButtonIcon}
iconType="SimpleLineIcons" iconType="MaterialCommunityIcons"
onPress={() => handleFollowUnfollowUser(isFollowing ? false : true)} onPress={() => handleFollowUnfollowUser(!isFollowing)}
size={16} size={20}
style={styles.insetIconStyle}
color="#c1c5c7" color="#c1c5c7"
/> />
)} )}
{isProfileLoading ? ( {isProfileLoading ? (
<ActivityIndicator style={styles.activityIndicator} /> <ActivityIndicator style={styles.activityIndicator} />
) : ( ) : (
<IconButton <DropdownButton
backgroundColor="transparent" isHasChildIcon
name={ignoreButtonIcon} iconName="more-vert"
iconType="SimpleLineIcons" options={dropdownOpions}
onPress={() => handleMuteUnmuteUser(isMuted ? false : true)} onSelect={this._handleOnDropdownSelect}
size={16} noHighlight
style={styles.insetIconStyle} iconStyle={styles.dropdownIconStyle}
color="#c1c5c7" dropdownStyle={styles.dropdownStyle}
/> />
)} )}
</Fragment> </Fragment>

View File

@ -43,6 +43,7 @@ class UpvoteContainer extends PureComponent {
isLoggedIn, isLoggedIn,
isShowPayoutValue, isShowPayoutValue,
upvotePercent, upvotePercent,
pinCode,
} = this.props; } = this.props;
let author; let author;
let isVoted; let isVoted;
@ -50,10 +51,10 @@ class UpvoteContainer extends PureComponent {
let permlink; let permlink;
if (content) { if (content) {
author = content.author; ({ author } = content);
isVoted = content.is_voted; isVoted = content.is_voted;
pendingPayoutValue = content.pending_payout_value; pendingPayoutValue = content.pending_payout_value;
permlink = content.permlink; ({ permlink } = content);
} }
return ( return (
@ -68,6 +69,7 @@ class UpvoteContainer extends PureComponent {
pendingPayoutValue={pendingPayoutValue} pendingPayoutValue={pendingPayoutValue}
permlink={permlink} permlink={permlink}
upvotePercent={upvotePercent} upvotePercent={upvotePercent}
pinCode={pinCode}
/> />
); );
} }
@ -76,7 +78,7 @@ class UpvoteContainer extends PureComponent {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
isLoggedIn: state.application.isLoggedIn, isLoggedIn: state.application.isLoggedIn,
upvotePercent: state.application.upvotePercent, upvotePercent: state.application.upvotePercent,
pinCode: state.account.pin,
currentAccount: state.account.currentAccount, currentAccount: state.account.currentAccount,
}); });

View File

@ -75,7 +75,7 @@ class UpvoteView extends Component {
_upvoteContent = async () => { _upvoteContent = async () => {
const { const {
author, currentAccount, fetchPost, handleSetUpvotePercent, permlink, author, currentAccount, fetchPost, handleSetUpvotePercent, permlink, pinCode,
} = this.props; } = this.props;
const { sliderValue } = this.state; const { sliderValue } = this.state;
@ -92,6 +92,7 @@ class UpvoteView extends Component {
vote( vote(
currentAccount, currentAccount,
pinCode,
author, author,
permlink, permlink,
weight, weight,

View File

@ -6,6 +6,7 @@
"claim_reward_balance": "Claim Reward Balance", "claim_reward_balance": "Claim Reward Balance",
"transfer": "Transfer", "transfer": "Transfer",
"transfer_to_vesting": "Transfer To Vesting", "transfer_to_vesting": "Transfer To Vesting",
"transfer_from_savings": "Transfer From Savings",
"withdraw_vesting": "Power Down", "withdraw_vesting": "Power Down",
"fill_order": "Fill Order" "fill_order": "Fill Order"
}, },

View File

@ -1,13 +1,16 @@
{ {
"wallet": { "wallet": {
"curation_reward": "Curation Reward",
"author_reward": "Author Reward", "author_reward": "Author Reward",
"comment_benefactor_reward": "Comment Benefactor Reward", "claim_reward_balance_ok": "Reward balance claimed",
"claim_reward_balance": "Claim Reward Balance", "claim_reward_balance": "Claim Reward Balance",
"transfer": "Transfer", "comment_benefactor_reward": "Comment Benefactor Reward",
"curation_reward": "Curation Reward",
"fill_order": "Fill Order",
"transactions": "Transactions",
"transfer_from_savings": "Tasarruflardan Transfer",
"transfer_to_vesting": "Transfer To Vesting", "transfer_to_vesting": "Transfer To Vesting",
"withdraw_vesting": "withdraw_vesting", "transfer": "Transfer",
"fill_order": "Fill Order" "withdraw_vesting": "Withdraw Vesting"
}, },
"notification": { "notification": {
"vote": "beğendi", "vote": "beğendi",

View File

@ -5,17 +5,13 @@ import {
setAuthStatus, setAuthStatus,
getUserDataWithUsername, getUserDataWithUsername,
updateUserData, updateUserData,
setPinCode,
getPinCode,
updateCurrentUsername, updateCurrentUsername,
getUserData, getUserData,
} from '../../realm/realm'; } from '../../realm/realm';
import { encryptKey, decryptKey } from '../../utils/crypto'; import { encryptKey, decryptKey } from '../../utils/crypto';
import steemConnect from './steemConnectAPI'; import steemConnect from './steemConnectAPI';
export const Login = (username, password) => { export const login = async (username, password) => {
let publicKeys;
let privateKeys;
const resultKeys = { const resultKeys = {
active: null, active: null,
memo: null, memo: null,
@ -24,17 +20,17 @@ export const Login = (username, password) => {
}; };
let loginFlag = false; let loginFlag = false;
let avatar = ''; let avatar = '';
return new Promise((resolve, reject) => {
// Get user account data from STEEM Blockchain // Get user account data from STEEM Blockchain
getUser(username) const account = await getUser(username);
.then((account) => { if (!account) {
return Promise.reject(new Error('Invalid pin code, please check and try again'));
}
if (isLoggedInUser(username)) { if (isLoggedInUser(username)) {
reject(new Error('You are already logged in, please try to add another account')); return Promise.reject(new Error('You are already logged in, please try to add another account'));
} }
// Public keys of user // Public keys of user
publicKeys = { const publicKeys = {
active: account.active.key_auths.map(x => x[0]), active: account.active.key_auths.map(x => x[0]),
memo: account.memo_key, memo: account.memo_key,
owner: account.owner.key_auths.map(x => x[0]), owner: account.owner.key_auths.map(x => x[0]),
@ -42,7 +38,7 @@ export const Login = (username, password) => {
}; };
// Set private keys of user // Set private keys of user
privateKeys = getPrivateKeys(username, password); const privateKeys = getPrivateKeys(username, password);
// Check all keys // Check all keys
Object.keys(publicKeys).map((pubKey) => { Object.keys(publicKeys).map((pubKey) => {
@ -51,13 +47,12 @@ export const Login = (username, password) => {
resultKeys[pubKey] = publicKeys[pubKey]; resultKeys[pubKey] = publicKeys[pubKey];
} }
}); });
let jsonMetadata; let jsonMetadata;
try { try {
jsonMetadata = JSON.parse(account.json_metadata) || ''; jsonMetadata = JSON.parse(account.json_metadata) || '';
} catch (err) { } catch (err) {
jsonMetadata = ''; jsonMetadata = '';
// TODO: handle wrong json format properly
// reject(new Error(err));
} }
if (Object.keys(jsonMetadata).length !== 0) { if (Object.keys(jsonMetadata).length !== 0) {
avatar = jsonMetadata.profile.profile_image || ''; avatar = jsonMetadata.profile.profile_image || '';
@ -77,22 +72,11 @@ export const Login = (username, password) => {
account.local = userData; account.local = userData;
// Save user data to Realm DB // Save user data to Realm DB
setUserData(userData) await setUserData(userData);
.then(() => { await updateCurrentUsername(account.name);
resolve({ ...account, password }); return ({ ...account, password });
updateCurrentUsername(account.name);
})
.catch(() => {
reject(new Error('Invalid credentials, please check and try again'));
});
} else {
reject(new Error('Invalid credentials, please check and try again'));
} }
}) return Promise.reject(new Error('Invalid pin code, please check and try again'));
.catch(() => {
reject(new Error('Invalid credentials, please check and try again'));
});
});
}; };
export const loginWithSC2 = async (accessToken) => { export const loginWithSC2 = async (accessToken) => {
@ -104,7 +88,7 @@ export const loginWithSC2 = async (accessToken) => {
try { try {
const jsonMetadata = JSON.parse(account.account.json_metadata); const jsonMetadata = JSON.parse(account.account.json_metadata);
if (Object.keys(jsonMetadata).length !== 0) { if (Object.keys(jsonMetadata).length !== 0) {
avatar = jsonMetadata.profile.profile_image; avatar = jsonMetadata.profile.profile_image || '';
} }
} catch (error) { } catch (error) {
reject(new Error('Invalid credentials, please check and try again')); reject(new Error('Invalid credentials, please check and try again'));
@ -120,26 +104,15 @@ export const loginWithSC2 = async (accessToken) => {
accessToken: '', accessToken: '',
}; };
const authData = {
isLoggedIn: true,
currentUsername: account.account.name,
};
if (isLoggedInUser(account.account.name)) { if (isLoggedInUser(account.account.name)) {
reject(new Error('You are already logged in, please try to add another account')); reject(new Error('You are already logged in, please try to add another account'));
} }
setAuthStatus(authData)
.then(() => {
setUserData(userData) setUserData(userData)
.then(() => { .then(() => {
account.account.username = account.account.name; account.account.username = account.account.name;
resolve({ ...account.account, accessToken });
updateCurrentUsername(account.account.name); updateCurrentUsername(account.account.name);
}) resolve({ ...account.account, accessToken });
.catch((error) => {
reject(error);
});
}) })
.catch((error) => { .catch((error) => {
reject(error); reject(error);
@ -147,89 +120,21 @@ export const loginWithSC2 = async (accessToken) => {
}); });
}; };
export const setUserDataWithPinCode = data => new Promise((resolve, reject) => { export const setUserDataWithPinCode = async (data) => {
let updatedUserData;
const result = getUserDataWithUsername(data.username); const result = getUserDataWithUsername(data.username);
const userData = result[0]; const userData = result[0];
const privateKeys = getPrivateKeys(userData.username, data.password); const privateKeys = getPrivateKeys(userData.username, data.password);
if (userData.authType === 'masterKey') { const updatedUserData = {
updatedUserData = {
username: userData.username, username: userData.username,
authType: 'masterKey', authType: userData.authType,
masterKey: encryptKey(data.password, data.pinCode), accessToken: userData.authType === 'steemConnect' ? encryptKey(data.accessToken, data.pinCode) : '',
masterKey: userData.authType === 'masterKey' ? encryptKey(data.password, data.pinCode) : '',
postingKey: encryptKey(privateKeys.posting.toString(), data.pinCode), postingKey: encryptKey(privateKeys.posting.toString(), data.pinCode),
activeKey: encryptKey(privateKeys.active.toString(), data.pinCode), activeKey: encryptKey(privateKeys.active.toString(), data.pinCode),
memoKey: encryptKey(privateKeys.memo.toString(), data.pinCode), memoKey: encryptKey(privateKeys.memo.toString(), data.pinCode),
}; };
} else if (userData.authType === 'steemConnect') {
updatedUserData = {
username: userData.username,
authType: 'steemConnect',
accessToken: encryptKey(data.accessToken, data.pinCode),
masterKey: '',
postingKey: encryptKey(privateKeys.posting.toString(), data.pinCode),
activeKey: encryptKey(privateKeys.active.toString(), data.pinCode),
memoKey: encryptKey(privateKeys.memo.toString(), data.pinCode),
};
}
updateUserData(updatedUserData)
.then((response) => {
const authData = {
isLoggedIn: true,
currentUsername: userData.username,
};
setAuthStatus(authData)
.then(() => {
const encriptedPinCode = encryptKey(data.pinCode, 'pin-code');
setPinCode(encriptedPinCode)
.then(() => {
resolve(response);
})
.catch((error) => {
reject(error);
});
})
.catch((error) => {
reject(error);
});
})
.catch((err) => {
reject(err);
});
});
export const updatePinCode = async (data) => {
let updatedUserData;
const users = await getUserData();
if (users.length > 0) {
users.forEach(async (userData) => {
const password = decryptKey(userData.masterKey, data.oldPinCode);
const privateKeys = getPrivateKeys(userData.username, password);
if (userData.authType === 'masterKey') {
updatedUserData = {
username: userData.username,
authType: 'masterKey',
masterKey: encryptKey(password, data.pinCode),
postingKey: encryptKey(privateKeys.posting.toString(), data.pinCode),
activeKey: encryptKey(privateKeys.active.toString(), data.pinCode),
memoKey: encryptKey(privateKeys.memo.toString(), data.pinCode),
};
} else if (userData.authType === 'steemConnect') {
updatedUserData = {
username: userData.username,
authType: 'steemConnect',
accessToken: encryptKey(data.accessToken, data.pinCode),
masterKey: '',
postingKey: encryptKey(privateKeys.posting.toString(), data.pinCode),
activeKey: encryptKey(privateKeys.active.toString(), data.pinCode),
memoKey: encryptKey(privateKeys.memo.toString(), data.pinCode),
};
}
const response = await updateUserData(updatedUserData); const response = await updateUserData(updatedUserData);
const authData = { const authData = {
@ -238,9 +143,37 @@ export const updatePinCode = async (data) => {
}; };
await setAuthStatus(authData); await setAuthStatus(authData);
const encriptedPinCode = encryptKey(data.pinCode, 'pin-code'); return (response);
await setPinCode(encriptedPinCode); };
export const updatePinCode = async (data) => {
let password = null;
let accessToken = null;
const users = await getUserData();
if (users.length > 0) {
users.forEach(async (userData) => {
if (userData.authType === 'masterKey') {
password = decryptKey(userData.masterKey, data.oldPinCode);
} else if (userData.authType === 'steemConnect') {
accessToken = decryptKey(userData.accessToken, data.oldPinCode);
}
const privateKeys = getPrivateKeys(userData.username, password);
const updatedUserData = {
username: userData.username,
authType: userData.authType,
accessToken: userData.authType === 'steemConnect' ? encryptKey(accessToken, data.pinCode) : '',
masterKey: userData.authType === 'masterKey' ? encryptKey(password, data.pinCode) : '',
postingKey: encryptKey(privateKeys.posting.toString(), data.pinCode),
activeKey: encryptKey(privateKeys.active.toString(), data.pinCode),
memoKey: encryptKey(privateKeys.memo.toString(), data.pinCode),
};
const response = await updateUserData(updatedUserData);
const authData = {
isLoggedIn: true,
currentUsername: userData.username,
};
await setAuthStatus(authData);
return response; return response;
}); });
} }
@ -252,9 +185,13 @@ export const verifyPinCode = async (data) => {
let account = null; let account = null;
let loginFlag = false; let loginFlag = false;
if (result.length > 0) { if (result.length > 0) {
if (userData.masterKey || userData.accessToken) {
if (userData.authType === 'steemConnect') { if (userData.authType === 'steemConnect') {
const accessToken = decryptKey(userData.accessToken, data.pinCode); let accessToken;
try {
accessToken = decryptKey(userData.accessToken, data.pinCode);
} catch (error) {
return Promise.reject(new Error('Invalid pin code, please check and try again'));
}
await steemConnect.setAccessToken(accessToken); await steemConnect.setAccessToken(accessToken);
account = await steemConnect.me(); account = await steemConnect.me();
if (account) { if (account) {
@ -263,7 +200,6 @@ export const verifyPinCode = async (data) => {
} else if (userData.authType === 'masterKey') { } else if (userData.authType === 'masterKey') {
const password = decryptKey(userData.masterKey, data.pinCode); const password = decryptKey(userData.masterKey, data.pinCode);
account = await getUser(data.username); account = await getUser(data.username);
// Public keys of user // Public keys of user
const publicKeys = { const publicKeys = {
active: account.active.key_auths.map(x => x[0]), active: account.active.key_auths.map(x => x[0]),
@ -281,19 +217,7 @@ export const verifyPinCode = async (data) => {
} }
}); });
} }
} else {
const encriptedPinCode = await getPinCode();
const pinCode = decryptKey(encriptedPinCode, 'pin-code');
if (pinCode === data.pinCode) {
const res = await setUserDataWithPinCode(data);
if (res) {
loginFlag = true;
} }
}
}
}
return new Promise((resolve, reject) => {
if (loginFlag) { if (loginFlag) {
const authData = { const authData = {
isLoggedIn: true, isLoggedIn: true,
@ -306,18 +230,10 @@ export const verifyPinCode = async (data) => {
activeKey: decryptKey(userData.activeKey, data.pinCode), activeKey: decryptKey(userData.activeKey, data.pinCode),
memoKey: decryptKey(userData.memoKey, data.pinCode), memoKey: decryptKey(userData.memoKey, data.pinCode),
}; };
setAuthStatus(authData) await setAuthStatus(authData);
.then(() => { return (response);
resolve(response);
})
.catch(() => {
// TODO: create function for throw error
reject(new Error('Unknown error, please contact to eSteem.'));
});
} else {
reject(new Error('Invalid pin code, please check and try again'));
} }
}); return Promise.reject(new Error('Invalid pin code, please check and try again'));
}; };
export const switchAccount = username => new Promise((resolve, reject) => { export const switchAccount = username => new Promise((resolve, reject) => {

View File

@ -1,5 +1,7 @@
import { Client, PrivateKey } from 'dsteem'; import { Client, PrivateKey } from 'dsteem';
import steemConnect from 'steemconnect'; import steemConnect from 'steemconnect';
import Config from 'react-native-config';
import { getServer, getPinCode } from '../../realm/realm'; import { getServer, getPinCode } from '../../realm/realm';
import { getUnreadActivityCount } from '../esteem/esteem'; import { getUnreadActivityCount } from '../esteem/esteem';
@ -31,7 +33,7 @@ const _getClient = async () => {
_getClient(); _getClient();
export const getDigitPinCode = async () => decryptKey(await getPinCode(), 'pin-code'); export const getDigitPinCode = pin => decryptKey(pin, Config.PIN_KEY);
/** /**
* @method getAccount get account data * @method getAccount get account data
@ -194,8 +196,8 @@ export const getIsMuted = async (username, targetUsername) => {
return false; return false;
}; };
export const ignoreUser = async (currentAccount, data) => { export const ignoreUser = async (currentAccount, pin, data) => {
const digitPinCode = await getDigitPinCode(); const digitPinCode = getDigitPinCode(pin);
if (currentAccount.local.authType === AUTH_TYPE.MASTER_KEY) { if (currentAccount.local.authType === AUTH_TYPE.MASTER_KEY) {
const key = decryptKey(currentAccount.local.postingKey, digitPinCode); const key = decryptKey(currentAccount.local.postingKey, digitPinCode);
@ -358,8 +360,8 @@ export const getPostWithComments = async (user, permlink) => {
* @param vote vote object(author, permlink, voter, weight) * @param vote vote object(author, permlink, voter, weight)
* @param postingKey private posting key * @param postingKey private posting key
*/ */
export const vote = async (currentAccount, author, permlink, weight) => { export const vote = async (currentAccount, pin, author, permlink, weight) => {
const digitPinCode = await getDigitPinCode(); const digitPinCode = getDigitPinCode(pin);
if (currentAccount.local.authType === AUTH_TYPE.MASTER_KEY) { if (currentAccount.local.authType === AUTH_TYPE.MASTER_KEY) {
const key = decryptKey(currentAccount.local.postingKey, digitPinCode); const key = decryptKey(currentAccount.local.postingKey, digitPinCode);
@ -443,8 +445,8 @@ export const transferToken = (data, activeKey) => {
}); });
}; };
export const followUser = async (currentAccount, data) => { export const followUser = async (currentAccount, pin, data) => {
const digitPinCode = await getDigitPinCode(); const digitPinCode = getDigitPinCode(pin);
if (currentAccount.local.authType === AUTH_TYPE.MASTER_KEY) { if (currentAccount.local.authType === AUTH_TYPE.MASTER_KEY) {
const key = decryptKey(currentAccount.local.postingKey, digitPinCode); const key = decryptKey(currentAccount.local.postingKey, digitPinCode);
@ -484,8 +486,8 @@ export const followUser = async (currentAccount, data) => {
} }
}; };
export const unfollowUser = async (currentAccount, data) => { export const unfollowUser = async (currentAccount, pin, data) => {
const digitPinCode = await getDigitPinCode(); const digitPinCode = getDigitPinCode(pin);
if (currentAccount.local.authType === AUTH_TYPE.MASTER_KEY) { if (currentAccount.local.authType === AUTH_TYPE.MASTER_KEY) {
const key = decryptKey(currentAccount.local.postingKey, digitPinCode); const key = decryptKey(currentAccount.local.postingKey, digitPinCode);
@ -620,6 +622,7 @@ export const lookupAccounts = async (username) => {
*/ */
export const postContent = async ( export const postContent = async (
account, account,
pin,
parentAuthor, parentAuthor,
parentPermlink, parentPermlink,
permlink, permlink,
@ -630,7 +633,7 @@ export const postContent = async (
voteWeight = null, voteWeight = null,
) => { ) => {
const { name: author } = account; const { name: author } = account;
const digitPinCode = await getDigitPinCode(); const digitPinCode = getDigitPinCode(pin);
if (account.local.authType === AUTH_TYPE.MASTER_KEY) { if (account.local.authType === AUTH_TYPE.MASTER_KEY) {
const opArray = [ const opArray = [
@ -722,8 +725,8 @@ export const postContent = async (
}; };
// Re-blog // Re-blog
export const reblog = async (account, author, permlink) => { export const reblog = async (account, pinCode, author, permlink) => {
const pin = await getDigitPinCode(); const pin = getDigitPinCode(pinCode);
if (account.local.authType === AUTH_TYPE.MASTER_KEY) { if (account.local.authType === AUTH_TYPE.MASTER_KEY) {
const key = decryptKey(account.local.postingKey, pin); const key = decryptKey(account.local.postingKey, pin);

View File

@ -6,6 +6,7 @@ import {
UPDATE_CURRENT_ACCOUNT, UPDATE_CURRENT_ACCOUNT,
UPDATE_UNREAD_ACTIVITY_COUNT, UPDATE_UNREAD_ACTIVITY_COUNT,
REMOVE_OTHER_ACCOUNT, REMOVE_OTHER_ACCOUNT,
SET_PIN_CODE,
} from '../constants/constants'; } from '../constants/constants';
export const fetchAccountFromSteem = (username, password) => (dispatch) => { export const fetchAccountFromSteem = (username, password) => (dispatch) => {
@ -43,3 +44,8 @@ export const removeOtherAccount = data => ({
type: REMOVE_OTHER_ACCOUNT, type: REMOVE_OTHER_ACCOUNT,
payload: data, payload: data,
}); });
export const setPinCode = data => ({
type: SET_PIN_CODE,
payload: data,
});

View File

@ -28,6 +28,7 @@ export const FETCHING_ACCOUNT = 'FETCHING_ACCOUNT';
export const REMOVE_OTHER_ACCOUNT = 'REMOVE_OTHER_ACCOUNT'; export const REMOVE_OTHER_ACCOUNT = 'REMOVE_OTHER_ACCOUNT';
export const UPDATE_CURRENT_ACCOUNT = 'UPDATE_CURRENT_ACCOUNT'; export const UPDATE_CURRENT_ACCOUNT = 'UPDATE_CURRENT_ACCOUNT';
export const UPDATE_UNREAD_ACTIVITY_COUNT = 'UPDATE_UNREAD_ACTIVITY_COUNT'; export const UPDATE_UNREAD_ACTIVITY_COUNT = 'UPDATE_UNREAD_ACTIVITY_COUNT';
export const SET_PIN_CODE = 'SET_PIN_CODE';
// UI // UI
export const IS_COLLAPSE_POST_BUTTON = 'IS_COLLAPSE_POST_BUTTON'; export const IS_COLLAPSE_POST_BUTTON = 'IS_COLLAPSE_POST_BUTTON';

View File

@ -4,9 +4,9 @@ import {
ADD_OTHER_ACCOUNT, ADD_OTHER_ACCOUNT,
UPDATE_CURRENT_ACCOUNT, UPDATE_CURRENT_ACCOUNT,
UPDATE_UNREAD_ACTIVITY_COUNT, UPDATE_UNREAD_ACTIVITY_COUNT,
LOGOUT,
REMOVE_OTHER_ACCOUNT, REMOVE_OTHER_ACCOUNT,
LOGOUT_FAIL, LOGOUT_FAIL,
SET_PIN_CODE,
} from '../constants/constants'; } from '../constants/constants';
const initialState = { const initialState = {
@ -16,6 +16,7 @@ const initialState = {
hasError: false, hasError: false,
errorMessage: null, errorMessage: null,
isLogingOut: false, isLogingOut: false,
pin: null,
}; };
export default function (state = initialState, action) { export default function (state = initialState, action) {
@ -77,11 +78,12 @@ export default function (state = initialState, action) {
...state, ...state,
isLogingOut: true, isLogingOut: true,
}; };
// case LOGOUT_SUCCESS:
// return { case SET_PIN_CODE:
// ...state, return {
// initialState, ...state,
// }; pin: action.payload,
};
default: default:
return state; return state;

View File

@ -91,38 +91,39 @@ class ApplicationContainer extends Component {
}; };
_getUserData = async () => { _getUserData = async () => {
const { dispatch } = this.props; const { dispatch, pinCode } = this.props;
let realmData; let realmData;
let authStatus;
let currentUsername; let currentUsername;
await getAuthStatus().then((res) => { await getAuthStatus().then((res) => {
authStatus = res; ({ currentUsername } = res);
currentUsername = res.currentUsername; if (res) {
getUserData().then((userData) => { getUserData().then((userData) => {
if (userData.length > 0) { if (userData.length > 0) {
realmData = userData; realmData = userData;
userData.forEach((accountData) => { userData.forEach((accountData) => {
dispatch( dispatch(addOtherAccount({ username: accountData.username }));
addOtherAccount({ username: accountData.username }),
);
}); });
} }
}); });
}
}); });
if (realmData) { if (realmData) {
await getUser(currentUsername) await getUser(currentUsername)
.then((accountData) => { .then(async (accountData) => {
dispatch(login(true)); dispatch(login(true));
const isExistUser = await getExistUser();
const realmObject = realmData.filter(data => data.username === currentUsername); const realmObject = realmData.filter(data => data.username === currentUsername);
accountData.local = realmObject[0]; [accountData.local] = realmObject;
dispatch(updateCurrentAccount(accountData)); dispatch(updateCurrentAccount(accountData));
// If in dev mode pin code does not show // If in dev mode pin code does not show
if (__DEV__ === false) { // eslint-disable-next-line
if (!isExistUser || !pinCode) {
dispatch(openPinCodeModal()); dispatch(openPinCodeModal());
} }
this._connectNotificationServer(accountData.name); this._connectNotificationServer(accountData.name);
@ -142,12 +143,12 @@ class ApplicationContainer extends Component {
getSettings().then((response) => { getSettings().then((response) => {
if (response) { if (response) {
response.isDarkTheme && dispatch(isDarkTheme(response.isDarkTheme)); if (response.isDarkTheme) dispatch(isDarkTheme(response.isDarkTheme));
response.language && dispatch(setLanguage(response.language)); if (response.language) dispatch(setLanguage(response.language));
response.currency && dispatch(setCurrency(response.currency)); if (response.currency) dispatch(setCurrency(response.currency));
response.notification && dispatch(isNotificationOpen(response.notification)); if (response.notification) dispatch(isNotificationOpen(response.notification));
response.server && dispatch(setApi(response.server)); if (response.server) dispatch(setApi(response.server));
response.upvotePercent && dispatch(setUpvotePercent(Number(response.upvotePercent))); if (response.upvotePercent) dispatch(setUpvotePercent(Number(response.upvotePercent)));
this.setState({ isReady: true }); this.setState({ isReady: true });
} }
@ -158,7 +159,7 @@ class ApplicationContainer extends Component {
const { dispatch, unreadActivityCount } = this.props; const { dispatch, unreadActivityCount } = this.props;
const ws = new WebSocket(`${Config.ACTIVITY_WEBSOCKET_URL}?user=${username}`); const ws = new WebSocket(`${Config.ACTIVITY_WEBSOCKET_URL}?user=${username}`);
ws.onmessage = (e) => { ws.onmessage = () => {
// a message was received // a message was received
dispatch(updateUnreadActivityCount(unreadActivityCount + 1)); dispatch(updateUnreadActivityCount(unreadActivityCount + 1));
}; };
@ -188,9 +189,7 @@ class ApplicationContainer extends Component {
}; };
_logout = () => { _logout = () => {
const { const { otherAccounts, currentAccountUsername, dispatch } = this.props;
otherAccounts, currentAccountUsername, dispatch,
} = this.props;
removeUserData(currentAccountUsername) removeUserData(currentAccountUsername)
.then(() => { .then(() => {
@ -210,8 +209,7 @@ class ApplicationContainer extends Component {
dispatch(removeOtherAccount(currentAccountUsername)); dispatch(removeOtherAccount(currentAccountUsername));
dispatch(logoutDone()); dispatch(logoutDone());
}) })
.catch((err) => { .catch(() => {
alert('err');
}); });
}; };
@ -222,11 +220,11 @@ class ApplicationContainer extends Component {
const realmData = getUserDataWithUsername(targetAccountUsername); const realmData = getUserDataWithUsername(targetAccountUsername);
const _currentAccount = accountData; const _currentAccount = accountData;
_currentAccount.username = accountData.name; _currentAccount.username = accountData.name;
_currentAccount.local = realmData[0]; [_currentAccount.local] = realmData;
dispatch(updateCurrentAccount(_currentAccount)); dispatch(updateCurrentAccount(_currentAccount));
}); });
} };
render() { render() {
const { selectedLanguage } = this.props; const { selectedLanguage } = this.props;
@ -256,6 +254,7 @@ const mapStateToProps = state => ({
unreadActivityCount: state.account.currentAccount.unread_activity_count, unreadActivityCount: state.account.currentAccount.unread_activity_count,
currentAccountUsername: state.account.currentAccount.name, currentAccountUsername: state.account.currentAccount.name,
otherAccounts: state.account.otherAccounts, otherAccounts: state.account.otherAccounts,
pinCode: state.account.pin,
}); });
export default connect(mapStateToProps)(ApplicationContainer); export default connect(mapStateToProps)(ApplicationContainer);

View File

@ -203,7 +203,7 @@ class EditorContainer extends Component {
}; };
_submitPost = async (fields) => { _submitPost = async (fields) => {
const { navigation, currentAccount } = this.props; const { navigation, currentAccount, pinCode } = this.props;
if (currentAccount) { if (currentAccount) {
this.setState({ isPostSending: true }); this.setState({ isPostSending: true });
@ -217,6 +217,7 @@ class EditorContainer extends Component {
await postContent( await postContent(
currentAccount, currentAccount,
pinCode,
'', '',
parentPermlink, parentPermlink,
permlink, permlink,
@ -237,7 +238,7 @@ class EditorContainer extends Component {
}; };
_submitReply = async (fields) => { _submitReply = async (fields) => {
const { currentAccount } = this.props; const { currentAccount, pinCode } = this.props;
if (currentAccount) { if (currentAccount) {
this.setState({ isPostSending: true }); this.setState({ isPostSending: true });
@ -253,6 +254,7 @@ class EditorContainer extends Component {
await postContent( await postContent(
currentAccount, currentAccount,
pinCode,
parentAuthor, parentAuthor,
parentPermlink, parentPermlink,
permlink, permlink,
@ -343,7 +345,7 @@ class EditorContainer extends Component {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
isLoggedIn: state.application.isLoggedIn, isLoggedIn: state.application.isLoggedIn,
pinCode: state.account.pin,
currentAccount: state.account.currentAccount, currentAccount: state.account.currentAccount,
}); });

View File

@ -1,11 +1,21 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { Alert, Linking } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
// Services and Actions // Services and Actions
import { login } from '../../../providers/steem/auth';
import { lookupAccounts } from '../../../providers/steem/dsteem';
import {
failedAccount,
addOtherAccount,
updateCurrentAccount,
} from '../../../redux/actions/accountAction';
import { login as loginAction, openPinCodeModal } from '../../../redux/actions/applicationActions';
// Middleware // Middleware
// Constants // Constants
import ROUTES from '../../../constants/routeNames';
// Utilities // Utilities
@ -21,15 +31,61 @@ import LoginScreen from '../screen/loginScreen';
class LoginContainer extends PureComponent { class LoginContainer extends PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = {};
this.state = {
isLoading: false,
};
} }
// Component Life Cycle Functions // Component Life Cycle Functions
// Component Functions // Component Functions
_handleOnPressLogin = (username, password) => {
const { dispatch, setPinCodeState } = this.props;
this.setState({ isLoading: true });
login(username, password)
.then((result) => {
if (result) {
dispatch(updateCurrentAccount({ ...result }));
dispatch(addOtherAccount({ username: result.name }));
dispatch(openPinCodeModal());
setPinCodeState({ navigateTo: ROUTES.DRAWER.MAIN });
dispatch(loginAction(true));
}
})
.catch((err) => {
// TODO: Change with global error handling
Alert.alert('Error', err.message);
dispatch(failedAccount(err.message));
this.setState({ isLoading: false });
});
};
_getAccountsWithUsername = async (username) => {
const validUsers = await lookupAccounts(username);
return validUsers;
};
_handleSignUp = () => {
Linking.openURL('https://signup.steemit.com/?ref=esteem').catch(err => alert('An error occurred', err));
};
render() { render() {
return <LoginScreen {...this.props} />; const { isLoading } = this.state;
const { navigation, setPinCodeState } = this.props;
return (
<LoginScreen
handleOnPressLogin={this._handleOnPressLogin}
getAccountsWithUsername={this._getAccountsWithUsername}
handleSignUp={this._handleSignUp}
isLoading={isLoading}
navigation={navigation}
setPinCodeState={setPinCodeState}
/>
);
} }
} }

View File

@ -1,30 +1,20 @@
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { import { View, StatusBar, Platform } from 'react-native';
View, Linking, StatusBar, Platform, Alert,
} from 'react-native';
import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view'; import { KeyboardAwareScrollView } from 'react-native-keyboard-aware-scroll-view';
import ScrollableTabView from '@esteemapp/react-native-scrollable-tab-view'; import ScrollableTabView from '@esteemapp/react-native-scrollable-tab-view';
import { injectIntl } from 'react-intl'; import { injectIntl } from 'react-intl';
// Actions // Actions
import { import SteemConnect from '../../steem-connect/steemConnect';
failedAccount,
addOtherAccount,
updateCurrentAccount,
} from '../../../redux/actions/accountAction';
import { login as loginAction, openPinCodeModal } from '../../../redux/actions/applicationActions';
// Internal Components // Internal Components
import { FormInput } from '../../../components/formInput'; import { FormInput } from '../../../components/formInput';
import { InformationArea } from '../../../components/informationArea'; import { InformationArea } from '../../../components/informationArea';
import { Login } from '../../../providers/steem/auth';
import { LoginHeader } from '../../../components/loginHeader'; import { LoginHeader } from '../../../components/loginHeader';
import { lookupAccounts } from '../../../providers/steem/dsteem';
import { MainButton } from '../../../components/mainButton'; import { MainButton } from '../../../components/mainButton';
import { Modal } from '../../../components'; import { Modal } from '../../../components';
import { TabBar } from '../../../components/tabBar'; import { TabBar } from '../../../components/tabBar';
import { TextButton } from '../../../components/buttons'; import { TextButton } from '../../../components/buttons';
import SteemConnect from '../../steem-connect/steemConnect';
// Constants // Constants
import { default as ROUTES } from '../../../constants/routeNames'; import { default as ROUTES } from '../../../constants/routeNames';
@ -40,51 +30,26 @@ class LoginScreen extends PureComponent {
this.state = { this.state = {
username: '', username: '',
password: '', password: '',
isLoading: false,
isUsernameValid: true, isUsernameValid: true,
keyboardIsOpen: false, keyboardIsOpen: false,
isModalOpen: false, isModalOpen: false,
}; };
} }
_handleOnPressLogin = () => {
const { dispatch, setPinCodeState } = this.props;
const { password, username } = this.state;
this.setState({ isLoading: true });
Login(username, password)
.then((result) => {
if (result) {
dispatch(updateCurrentAccount({ ...result }));
dispatch(addOtherAccount({ username: result.name }));
dispatch(openPinCodeModal());
setPinCodeState({ navigateTo: ROUTES.DRAWER.MAIN });
dispatch(loginAction(true));
}
})
.catch((err) => {
// TODO: Change with global error handling
Alert.alert('Error', err.message);
dispatch(failedAccount(err.message));
this.setState({ isLoading: false });
});
};
_handleUsernameChange = async (username) => {
await this.setState({ username });
const validUsers = await lookupAccounts(username);
const isValid = validUsers.includes(username);
this.setState({ isUsernameValid: isValid });
};
_handleOnPasswordChange = (value) => { _handleOnPasswordChange = (value) => {
this.setState({ password: value }); this.setState({ password: value });
}; };
_handleSignUp = () => { _handleUsernameChange = (username) => {
Linking.openURL('https://signup.steemit.com/?ref=esteem').catch(err => alert('An error occurred', err)); const { getAccountsWithUsername } = this.props;
this.setState({ username });
getAccountsWithUsername(username).then((res) => {
const isValid = res.includes(username);
this.setState({ isUsernameValid: isValid });
});
}; };
_handleOnModalToggle = () => { _handleOnModalToggle = () => {
@ -93,14 +58,16 @@ class LoginScreen extends PureComponent {
}; };
render() { render() {
const { navigation, intl, setPinCodeState } = this.props;
const { const {
navigation,
intl,
setPinCodeState,
handleOnPressLogin,
handleSignUp,
isLoading, isLoading,
username, } = this.props;
isUsernameValid, const {
keyboardIsOpen, username, isUsernameValid, keyboardIsOpen, password, isModalOpen,
password,
isModalOpen,
} = this.state; } = this.state;
return ( return (
@ -114,7 +81,7 @@ class LoginScreen extends PureComponent {
description={intl.formatMessage({ description={intl.formatMessage({
id: 'login.signin_title', id: 'login.signin_title',
})} })}
onPress={() => this._handleSignUp()} onPress={() => handleSignUp()}
rightButtonText={intl.formatMessage({ rightButtonText={intl.formatMessage({
id: 'login.signup', id: 'login.signup',
})} })}
@ -125,7 +92,7 @@ class LoginScreen extends PureComponent {
renderTabBar={() => ( renderTabBar={() => (
<TabBar <TabBar
style={styles.tabbar} style={styles.tabbar}
tabUnderlineDefaultWidth={100} // default containerWidth / (numberOfTabs * 4) tabUnderlineDefaultWidth={100}
tabUnderlineScaleX={2} // default 3 tabUnderlineScaleX={2} // default 3
activeColor="#357ce6" activeColor="#357ce6"
inactiveColor="#222" inactiveColor="#222"
@ -187,7 +154,7 @@ class LoginScreen extends PureComponent {
})} })}
/> />
<MainButton <MainButton
onPress={this._handleOnPressLogin} onPress={() => handleOnPressLogin(username, password)}
iconName="md-person" iconName="md-person"
iconColor="white" iconColor="white"
text={intl.formatMessage({ text={intl.formatMessage({

View File

@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { Alert } from 'react-native'; import { Alert } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { injectIntl } from 'react-intl'; import { injectIntl } from 'react-intl';
import Config from 'react-native-config';
import { import {
setUserDataWithPinCode, setUserDataWithPinCode,
@ -12,7 +13,10 @@ import {
// Actions & Services // Actions & Services
import { closePinCodeModal } from '../../../redux/actions/applicationActions'; import { closePinCodeModal } from '../../../redux/actions/applicationActions';
import { getExistUser, setExistUser, getUserDataWithUsername } from '../../../realm/realm'; import { getExistUser, setExistUser, getUserDataWithUsername } from '../../../realm/realm';
import { updateCurrentAccount } from '../../../redux/actions/accountAction'; import { updateCurrentAccount, setPinCode as savePinCode } from '../../../redux/actions/accountAction';
// Utils
import { encryptKey, decryptKey } from '../../../utils/crypto';
// Component // Component
import PinCodeScreen from '../screen/pinCodeScreen'; import PinCodeScreen from '../screen/pinCodeScreen';
@ -33,9 +37,10 @@ class PinCodeContainer extends Component {
// TODO: these text should move to view! // TODO: these text should move to view!
componentDidMount() { componentDidMount() {
this._getDataFromStorage().then(() => { this._getDataFromStorage().then(() => {
const { intl, isReset } = this.props; const { intl } = this.props;
const { isExistUser } = this.state; const { isExistUser } = this.state;
if (isExistUser || !isReset) {
if (isExistUser) {
this.setState({ this.setState({
informationText: intl.formatMessage({ informationText: intl.formatMessage({
id: 'pincode.enter_text', id: 'pincode.enter_text',
@ -62,22 +67,17 @@ class PinCodeContainer extends Component {
}); });
}); });
_setPinCode = pin => new Promise((resolve, reject) => { _resetPinCode = pin => new Promise((resolve, reject) => {
const { const {
currentAccount, currentAccount,
dispatch, dispatch,
accessToken, accessToken,
setWrappedComponentState,
navigateTo, navigateTo,
navigation, navigation,
intl, intl,
isReset,
} = this.props; } = this.props;
const { const { isOldPinVerified, oldPinCode } = this.state;
isExistUser, pinCode, isOldPinVerified, oldPinCode,
} = this.state;
if (isReset) {
const pinData = { const pinData = {
pinCode: pin, pinCode: pin,
password: currentAccount ? currentAccount.password : '', password: currentAccount ? currentAccount.password : '',
@ -92,6 +92,7 @@ class PinCodeContainer extends Component {
_currentAccount.local = response; _currentAccount.local = response;
dispatch(updateCurrentAccount({ ..._currentAccount })); dispatch(updateCurrentAccount({ ..._currentAccount }));
this._savePinCode(pin);
dispatch(closePinCodeModal()); dispatch(closePinCodeModal());
if (navigateTo) { if (navigateTo) {
@ -117,43 +118,17 @@ class PinCodeContainer extends Component {
reject(err); reject(err);
}); });
} }
} else if (isExistUser) { });
// If the user is exist, we are just checking to pin and navigating to home screen
const pinData = { _setFirstPinCode = pin => new Promise((resolve) => {
pinCode: pin, const {
password: currentAccount ? currentAccount.password : '', currentAccount,
username: currentAccount ? currentAccount.name : '', dispatch,
accessToken, accessToken,
}; navigateTo,
verifyPinCode(pinData) navigation,
.then((res) => { } = this.props;
setWrappedComponentState(res);
dispatch(closePinCodeModal());
const realmData = getUserDataWithUsername(currentAccount.name);
const _currentAccount = currentAccount;
_currentAccount.username = _currentAccount.name;
_currentAccount.local = realmData[0];
dispatch(updateCurrentAccount({ ..._currentAccount }));
if (navigateTo) {
navigation.navigate(navigateTo);
}
})
.catch((err) => {
Alert.alert('Warning', err.message);
reject(err);
});
} else if (!pinCode) {
// If the user is logging in for the first time, the user should set to pin
this.setState({
informationText: intl.formatMessage({
id: 'pincode.write_again',
}),
pinCode: pin,
});
resolve();
} else if (pinCode === pin) {
const pinData = { const pinData = {
pinCode: pin, pinCode: pin,
password: currentAccount ? currentAccount.password : '', password: currentAccount ? currentAccount.password : '',
@ -167,6 +142,7 @@ class PinCodeContainer extends Component {
dispatch(updateCurrentAccount({ ..._currentAccount })); dispatch(updateCurrentAccount({ ..._currentAccount }));
setExistUser(true).then(() => { setExistUser(true).then(() => {
this._savePinCode(pin);
dispatch(closePinCodeModal()); dispatch(closePinCodeModal());
if (navigateTo) { if (navigateTo) {
navigation.navigate(navigateTo); navigation.navigate(navigateTo);
@ -174,32 +150,120 @@ class PinCodeContainer extends Component {
resolve(); resolve();
}); });
}); });
});
_verifyPinCode = pin => new Promise((resolve, reject) => {
const {
currentAccount,
dispatch,
accessToken,
navigateTo,
navigation,
setWrappedComponentState,
} = this.props;
// If the user is exist, we are just checking to pin and navigating to home screen
const pinData = {
pinCode: pin,
password: currentAccount ? currentAccount.password : '',
username: currentAccount ? currentAccount.name : '',
accessToken,
};
verifyPinCode(pinData)
.then((res) => {
setWrappedComponentState(res);
this._savePinCode(pin);
const realmData = getUserDataWithUsername(currentAccount.name);
const _currentAccount = currentAccount;
_currentAccount.username = _currentAccount.name;
[_currentAccount.local] = realmData;
dispatch(updateCurrentAccount({ ..._currentAccount }));
dispatch(closePinCodeModal());
if (navigateTo) {
navigation.navigate(navigateTo);
}
})
.catch((err) => {
Alert.alert('Warning', err.message);
reject(err);
});
});
_savePinCode = (pin) => {
const { dispatch } = this.props;
const encryptedPin = encryptKey(pin, Config.PIN_KEY);
dispatch(savePinCode(encryptedPin));
}
_setPinCode = async (pin, isReset) => {
const {
intl, currentAccount, applicationPinCode,
} = this.props;
const {
isExistUser, pinCode,
} = this.state;
const realmData = getUserDataWithUsername(currentAccount.name);
const userData = realmData[0];
// For exist users
if (isReset) { await this._resetPinCode(pin); return true; }
if (isExistUser) {
if (!userData.accessToken && !userData.masterKey && applicationPinCode) {
const verifiedPin = decryptKey(applicationPinCode, Config.PIN_KEY);
if (verifiedPin === pin) {
await this._setFirstPinCode(pin);
} else { } else {
this.setState({ Alert.alert('Warning', 'Invalid pin code, please check and try again');
}
} else {
await this._verifyPinCode(pin);
}
return true;
}
// For new users
if (pinCode === pin) { await this._setFirstPinCode(pin); return true; }
if (!pinCode) {
// If the user is logging in for the first time, the user should set to pin
await this.setState({
informationText: intl.formatMessage({
id: 'pincode.write_again',
}),
pinCode: pin,
});
return Promise.resolve();
}
await this.setState({
informationText: intl.formatMessage({ informationText: intl.formatMessage({
id: 'pincode.write_again', id: 'pincode.write_again',
}), }),
}); });
setTimeout(() => { await setTimeout(() => {
this.setState({ this.setState({
informationText: 'setup screen', informationText: intl.formatMessage({
id: 'pincode.set_new',
}),
pinCode: null, pinCode: null,
}); });
resolve(); return Promise.resolve();
}, 1000); }, 1000);
} };
});
render() { render() {
const { currentAccount, intl } = this.props; const { currentAccount, intl, isReset } = this.props;
const { informationText, isExistUser } = this.state; const { informationText, isExistUser } = this.state;
return ( return (
<PinCodeScreen <PinCodeScreen
informationText={informationText} informationText={informationText}
setPinCode={this._setPinCode} setPinCode={pin => this._setPinCode(pin, isReset)}
showForgotButton={isExistUser} showForgotButton={isExistUser}
username={currentAccount.name} username={currentAccount.name}
intl={intl} intl={intl}
{...this.props}
/> />
); );
} }
@ -207,6 +271,7 @@ class PinCodeContainer extends Component {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
currentAccount: state.account.currentAccount, currentAccount: state.account.currentAccount,
applicationPinCode: state.account.pin,
}); });
export default injectIntl(connect(mapStateToProps)(PinCodeContainer)); export default injectIntl(connect(mapStateToProps)(PinCodeContainer));

View File

@ -11,6 +11,7 @@ class PinCodeScreen extends PureComponent {
super(props); super(props);
this.state = { this.state = {
pin: '', pin: '',
loading: false,
}; };
} }
@ -18,10 +19,12 @@ class PinCodeScreen extends PureComponent {
// Component Functions // Component Functions
_handleKeyboardOnPress = (value) => { _handleKeyboardOnPress = async (value) => {
const { setPinCode } = this.props; const { setPinCode } = this.props;
const { pin } = this.state; const { pin, loading } = this.state;
if (loading) {
return;
}
if (value === 'clear') { if (value === 'clear') {
this.setState({ pin: '' }); this.setState({ pin: '' });
return; return;
@ -31,14 +34,15 @@ class PinCodeScreen extends PureComponent {
if (pin.length < 3) { if (pin.length < 3) {
this.setState({ pin: newPin }); this.setState({ pin: newPin });
} else if (pin.length === 3) { } else if (pin.length === 3) {
this.setState({ pin: newPin }); await this.setState({ pin: newPin, loading: true });
setPinCode(`${pin}${value}`) setPinCode(`${pin}${value}`)
.then(() => { .then(() => {
// TODO: fix unmounted component error // TODO: fix unmounted component error
this.setState({ pin: '' }); this.setState({ pin: '', loading: false });
}) })
.catch(() => { .catch(() => {
this.setState({ pin: '' }); this.setState({ pin: '', loading: false });
}); });
} else if (pin.length > 3) { } else if (pin.length > 3) {
this.setState({ pin: `${value}` }); this.setState({ pin: `${value}` });
@ -49,7 +53,7 @@ class PinCodeScreen extends PureComponent {
const { const {
informationText, showForgotButton, username, intl, informationText, showForgotButton, username, intl,
} = this.props; } = this.props;
const { pin } = this.state; const { pin, loading } = this.state;
return ( return (
<View style={styles.container}> <View style={styles.container}>
@ -63,7 +67,7 @@ class PinCodeScreen extends PureComponent {
<Text style={styles.informationText}>{informationText}</Text> <Text style={styles.informationText}>{informationText}</Text>
</View> </View>
<View style={styles.animatedView}> <View style={styles.animatedView}>
<PinAnimatedInput pin={pin} /> <PinAnimatedInput pin={pin} loading={loading} />
</View> </View>
<View style={styles.numericKeyboardView}> <View style={styles.numericKeyboardView}>
<NumericKeyboard onPress={this._handleKeyboardOnPress} /> <NumericKeyboard onPress={this._handleKeyboardOnPress} />

View File

@ -62,8 +62,12 @@ class ProfileContainer extends Component {
}; };
componentWillReceiveProps(nextProps) { componentWillReceiveProps(nextProps) {
const { navigation, currentAccount, activeBottomTab, isLoggedIn } = this.props; const {
const currentUsername = currentAccount.name !== nextProps.currentAccount.name && nextProps.currentAccount.name; navigation, currentAccount, activeBottomTab, isLoggedIn,
} = this.props;
const currentUsername = currentAccount.name
!== nextProps.currentAccount.name
&& nextProps.currentAccount.name;
const isParamsChange = nextProps.navigation.state const isParamsChange = nextProps.navigation.state
&& navigation.state && navigation.state
&& nextProps.navigation.state.params && nextProps.navigation.state.params
@ -88,10 +92,6 @@ class ProfileContainer extends Component {
this._loadProfile(selectedUser && selectedUser.username); this._loadProfile(selectedUser && selectedUser.username);
} }
} }
_getReplies = async (user) => { _getReplies = async (user) => {
@ -102,39 +102,39 @@ class ProfileContainer extends Component {
comments: result, comments: result,
}); });
}) })
.catch((err) => {}); .catch(() => {});
}; };
_handleFollowUnfollowUser = async (isFollowAction) => { _handleFollowUnfollowUser = async (isFollowAction) => {
const { username, isFollowing } = this.state; const { username, isFollowing } = this.state;
const { currentAccount } = this.props; const { currentAccount, pinCode } = this.props;
this.setState({ this.setState({
isProfileLoading: true, isProfileLoading: true,
}); });
if (isFollowAction && !isFollowing) { if (isFollowAction && !isFollowing) {
this._followUser(currentAccount, currentAccount.name, username); this._followUser(currentAccount, pinCode, currentAccount.name, username);
} else { } else {
this._unfollowUser(currentAccount, currentAccount.name, username); this._unfollowUser(currentAccount, pinCode, currentAccount.name, username);
} }
}; };
_handleMuteUnmuteUser = async (isMuteAction) => { _handleMuteUnmuteUser = async (isMuteAction) => {
const { username, isMuted } = this.state; const { username } = this.state;
const { currentAccount } = this.props; const { currentAccount, pinCode } = this.props;
this.setState({ this.setState({
isProfileLoading: true, isProfileLoading: true,
}); });
if (isMuteAction) { if (isMuteAction) {
this._muteUser(currentAccount, currentAccount.name, username); this._muteUser(currentAccount, pinCode, currentAccount.name, username);
} }
}; };
_unfollowUser = (currentAccount, follower, following) => { _unfollowUser = (currentAccount, pinCode, follower, following) => {
unfollowUser(currentAccount, { unfollowUser(currentAccount, pinCode, {
follower, follower,
following, following,
}) })
@ -146,8 +146,8 @@ class ProfileContainer extends Component {
}); });
}; };
_followUser = (currentAccount, follower, following) => { _followUser = (currentAccount, pinCode, follower, following) => {
followUser(currentAccount, { followUser(currentAccount, pinCode, {
follower, follower,
following, following,
}) })
@ -159,8 +159,8 @@ class ProfileContainer extends Component {
}); });
}; };
_muteUser = async (currentAccount, follower, following) => { _muteUser = async (currentAccount, pinCode, follower, following) => {
ignoreUser(currentAccount, { ignoreUser(currentAccount, pinCode, {
follower, follower,
following, following,
}) })
@ -307,6 +307,7 @@ class ProfileContainer extends Component {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
isLoggedIn: state.application.isLoggedIn, isLoggedIn: state.application.isLoggedIn,
currentAccount: state.account.currentAccount, currentAccount: state.account.currentAccount,
pinCode: state.account.pin,
isDarkTheme: state.application.isDarkTheme, isDarkTheme: state.application.isDarkTheme,
activeBottomTab: state.ui.activeBottomTab, activeBottomTab: state.ui.activeBottomTab,
}); });

View File

@ -85,7 +85,7 @@ class SettingsContainer extends Component {
}; };
_handleToggleChanged = (action, actionType) => { _handleToggleChanged = (action, actionType) => {
const { dispatch, setPinCodeState } = this.props; const { dispatch } = this.props;
switch (actionType) { switch (actionType) {
case 'notification': case 'notification':
@ -97,11 +97,6 @@ class SettingsContainer extends Component {
dispatch(isDarkTheme(action)); dispatch(isDarkTheme(action));
setTheme(action); setTheme(action);
break; break;
case 'pincode':
// test
dispatch(openPinCodeModal());
setPinCodeState({ isReset: true });
break;
default: default:
break; break;
} }
@ -111,8 +106,8 @@ class SettingsContainer extends Component {
const { dispatch, setPinCodeState } = this.props; const { dispatch, setPinCodeState } = this.props;
switch (actionType) { switch (actionType) {
case 'pincode': case 'pincode':
dispatch(openPinCodeModal());
setPinCodeState({ isReset: true }); setPinCodeState({ isReset: true });
dispatch(openPinCodeModal());
break; break;
default: default:
break; break;

View File

@ -39,7 +39,7 @@ class SteemConnect extends PureComponent {
if (result) { if (result) {
dispatch(updateCurrentAccount({ ...result })); dispatch(updateCurrentAccount({ ...result }));
dispatch(addOtherAccount({ username: result.name })); dispatch(addOtherAccount({ username: result.name }));
dispatch(loginAction()); dispatch(loginAction(true));
dispatch(openPinCodeModal()); dispatch(openPinCodeModal());
setPinCodeState({ accessToken, navigateTo: ROUTES.DRAWER.MAIN }); setPinCodeState({ accessToken, navigateTo: ROUTES.DRAWER.MAIN });
} else { } else {

View File

@ -1,11 +1,3 @@
// TODO: Move all formats functions here!
// const imgRegex = /(https?:\/\/.*\.(?:tiff?|jpe?g|gif|png|svg|ico))/gim;
// const postRegex = /^https?:\/\/(.*)\/(.*)\/(@[\w\.\d-]+)\/(.*)/i;
// const youTubeRegex = /(?:https?:\/\/)?(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^& \n<]+)(?:[^ \n<]+)?/g;
// const vimeoRegex = /(https?:\/\/)?(www\.)?(?:vimeo)\.com.*(?:videos|video|channels|)\/([\d]+)/i;
// const dTubeRegex = /(https?:\/\/d.tube.#!\/v\/)(\w+)\/(\w+)/g;
export const getPostSummary = (postBody, length, isQuote) => { export const getPostSummary = (postBody, length, isQuote) => {
if (!postBody) { if (!postBody) {
return ''; return '';
@ -24,3 +16,13 @@ export const getPostSummary = (postBody, length, isQuote) => {
} }
return isQuote ? `"${postBody}..."` : `${postBody}...`; return isQuote ? `"${postBody}..."` : `${postBody}...`;
}; };
export const makeCountFriendly = (value) => {
if (!value) return value;
if (value >= 1000000) return `${intlFormat(value / 1000000)}M`;
if (value >= 1000) return `${intlFormat(value / 1000)}K`;
return intlFormat(value);
};
const intlFormat = num => new Intl.NumberFormat().format(Math.round(num * 10) / 10);

View File

@ -14,7 +14,7 @@ export const parsePost = (post, currentUserName, isSummary = false) => {
_post.json_metadata = JSON.parse(post.json_metadata); _post.json_metadata = JSON.parse(post.json_metadata);
_post.image = postImage(post.json_metadata, post.body); _post.image = postImage(post.json_metadata, post.body);
_post.pending_payout_value = parseFloat(post.pending_payout_value).toFixed(2); _post.pending_payout_value = parseFloat(post.pending_payout_value).toFixed(3);
_post.created = getTimeFromNow(post.created); _post.created = getTimeFromNow(post.created);
_post.vote_count = post.active_votes.length; _post.vote_count = post.active_votes.length;
_post.author_reputation = getReputation(post.author_reputation); _post.author_reputation = getReputation(post.author_reputation);
@ -121,7 +121,7 @@ export const protocolUrl2Obj = (url) => {
export const parseComments = (comments) => { export const parseComments = (comments) => {
comments.map((comment) => { comments.map((comment) => {
comment.pending_payout_value = parseFloat(comment.pending_payout_value).toFixed(2); comment.pending_payout_value = parseFloat(comment.pending_payout_value).toFixed(3);
comment.created = getTimeFromNow(comment.created); comment.created = getTimeFromNow(comment.created);
comment.vote_count = comment.active_votes.length; comment.vote_count = comment.active_votes.length;
comment.author_reputation = getReputation(comment.author_reputation); comment.author_reputation = getReputation(comment.author_reputation);

View File

@ -1,5 +1,5 @@
// import parseDate from './parseDate';
import parseToken from './parseToken'; import parseToken from './parseToken';
import parseDate from './parseDate';
import { vestsToSp } from './conversions'; import { vestsToSp } from './conversions';
export const getTransactionData = (transaction, walletData, formatNumber) => { export const getTransactionData = (transaction, walletData, formatNumber) => {
@ -14,7 +14,7 @@ export const getTransactionData = (transaction, walletData, formatNumber) => {
const opData = transaction[1].op[1]; const opData = transaction[1].op[1];
const { timestamp } = transaction[1]; const { timestamp } = transaction[1];
result.transDate = parseDate(timestamp); result.transDate = timestamp;
result.icon = 'local-activity'; result.icon = 'local-activity';
switch (result.opName) { switch (result.opName) {
@ -85,7 +85,7 @@ export const getTransactionData = (transaction, walletData, formatNumber) => {
result.value = `${formatNumber(vestsToSp(opVestingShares, walletData.steemPerMVests), { result.value = `${formatNumber(vestsToSp(opVestingShares, walletData.steemPerMVests), {
minimumFractionDigits: 3, minimumFractionDigits: 3,
})} SP`; })} SP`;
result.icon = 'money'; result.icon = 'attach-money';
result.details = `@${acc}`; result.details = `@${acc}`;
break; break;
case 'fill_order': case 'fill_order':