mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-23 05:13:04 +03:00
Merge pull request #943 from esteemapp/feature/boost-promote
Feature/boost promote
This commit is contained in:
commit
e2ddf4e402
@ -23,6 +23,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"@esteemapp/esteem-render-helpers": "^1.0.9",
|
||||
"@ptomasroos/react-native-multi-slider": "^1.0.0",
|
||||
"appcenter": "^1.10.0",
|
||||
"appcenter-analytics": "^1.10.0",
|
||||
"appcenter-crashes": "^1.10.0",
|
||||
@ -43,6 +44,7 @@
|
||||
"react-intl": "^2.7.2",
|
||||
"react-native": "0.59.8",
|
||||
"react-native-actionsheet": "^2.4.2",
|
||||
"react-native-autocomplete-input": "^4.1.0",
|
||||
"react-native-code-push": "esteemapp/react-native-code-push",
|
||||
"react-native-config": "^0.11.5",
|
||||
"react-native-datepicker": "^1.7.2",
|
||||
|
@ -1,23 +1,27 @@
|
||||
import Logo from './logo/logo';
|
||||
import { FormInput } from './formInput';
|
||||
import { CircularButton, TextButton, IconButton } from './buttons';
|
||||
import { FormInput } from './formInput';
|
||||
import { NumericKeyboard } from './numericKeyboard';
|
||||
import { PinAnimatedInput } from './pinAnimatedInput';
|
||||
import { SideMenu } from './sideMenu';
|
||||
import Modal from './modal';
|
||||
import { TextInput } from './textInput';
|
||||
import Icon from './icon';
|
||||
import Logo from './logo/logo';
|
||||
import Modal from './modal';
|
||||
import ScaleSlider from './scaleSlider/scaleSliderView';
|
||||
import UserListItem from './basicUIElements/view/userListItem/userListItem';
|
||||
|
||||
export {
|
||||
Logo,
|
||||
UserListItem,
|
||||
FormInput,
|
||||
CircularButton,
|
||||
TextButton,
|
||||
FormInput,
|
||||
Icon,
|
||||
IconButton,
|
||||
Logo,
|
||||
Modal,
|
||||
NumericKeyboard,
|
||||
PinAnimatedInput,
|
||||
ScaleSlider,
|
||||
SideMenu,
|
||||
Modal,
|
||||
Icon,
|
||||
TextButton,
|
||||
TextInput,
|
||||
UserListItem,
|
||||
};
|
||||
|
@ -1,3 +1,3 @@
|
||||
import Points from './container/pointsContainer';
|
||||
import Points from './view/pointsView';
|
||||
|
||||
export { Points };
|
||||
|
@ -88,7 +88,7 @@ class PointsView extends Component {
|
||||
<DropdownButton
|
||||
isHasChildIcon
|
||||
iconName="arrow-drop-down"
|
||||
options={['Transfer']}
|
||||
options={['Transfer', 'Promote']}
|
||||
noHighlight
|
||||
dropdownButtonStyle={styles.dropdownButtonStyle}
|
||||
onSelect={handleOnPressTransfer}
|
||||
|
51
src/components/scaleSlider/scaleSliderStyles.js
Normal file
51
src/components/scaleSlider/scaleSliderStyles.js
Normal file
@ -0,0 +1,51 @@
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
active: {
|
||||
textAlign: 'center',
|
||||
fontSize: 17,
|
||||
bottom: 10,
|
||||
color: '$primaryDarkText',
|
||||
},
|
||||
inactive: {
|
||||
flex: 1,
|
||||
textAlignVertical: 'center',
|
||||
textAlign: 'center',
|
||||
fontWeight: 'normal',
|
||||
color: '$primaryLightBackground',
|
||||
},
|
||||
line: {
|
||||
width: 14,
|
||||
height: 14,
|
||||
backgroundColor: '$primaryBlue',
|
||||
borderRadius: 7,
|
||||
borderWidth: 0,
|
||||
top: 12,
|
||||
zIndex: 999,
|
||||
},
|
||||
container: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
column: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
bottom: -20,
|
||||
},
|
||||
marker: {
|
||||
width: 35,
|
||||
height: 35,
|
||||
borderRadius: 17,
|
||||
backgroundColor: '$white',
|
||||
borderWidth: 1,
|
||||
position: 'absolute',
|
||||
borderColor: '$primaryBlue',
|
||||
},
|
||||
selected: {
|
||||
backgroundColor: '$primaryBlue',
|
||||
},
|
||||
track: {
|
||||
backgroundColor: '$primaryLightGray',
|
||||
},
|
||||
});
|
82
src/components/scaleSlider/scaleSliderView.js
Normal file
82
src/components/scaleSlider/scaleSliderView.js
Normal file
@ -0,0 +1,82 @@
|
||||
import React, { Component } from 'react';
|
||||
import { View, Dimensions, Text } from 'react-native';
|
||||
import MultiSlider from '@ptomasroos/react-native-multi-slider';
|
||||
import get from 'lodash/get';
|
||||
|
||||
import styles from './scaleSliderStyles';
|
||||
|
||||
export default class ScaleSliderView extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
activeValue: get(props, 'activeValue') || props.values[0],
|
||||
activeIndex: get(props, 'values', '').indexOf(get(props, 'activeValue')) || 0,
|
||||
};
|
||||
}
|
||||
|
||||
_renderMarker = () => <View style={styles.marker} />;
|
||||
|
||||
_valueChange = _values => {
|
||||
const { handleOnValueChange, values } = this.props;
|
||||
const index = _values[0] - 1;
|
||||
|
||||
this.setState({
|
||||
activeValue: values && values[index],
|
||||
activeIndex: index,
|
||||
});
|
||||
|
||||
if (handleOnValueChange) handleOnValueChange(values[index]);
|
||||
};
|
||||
|
||||
_renderItem = (value, index, activeIndex) => {
|
||||
const isActive = index <= activeIndex || index === 0;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<Text style={[isActive ? styles.active : styles.inactive]}>{value}</Text>
|
||||
<View style={[isActive ? styles.line : {}]} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
_renderScale = () => {
|
||||
const { values } = this.props;
|
||||
const { activeIndex } = this.state;
|
||||
|
||||
const items = [];
|
||||
|
||||
for (let i = 1; i <= values.length; i++) {
|
||||
items.push(this._renderItem(values[i - 1], i - 1, activeIndex));
|
||||
}
|
||||
|
||||
return items;
|
||||
};
|
||||
|
||||
render() {
|
||||
const { LRpadding, values } = this.props;
|
||||
const { activeIndex } = this.state;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style={[styles.column, { marginLeft: LRpadding, marginRight: LRpadding }]}>
|
||||
{this._renderScale()}
|
||||
</View>
|
||||
<View style={styles.container}>
|
||||
<MultiSlider
|
||||
trackStyle={styles.track}
|
||||
selectedStyle={styles.selected}
|
||||
sliderLength={Dimensions.get('window').width - LRpadding * 2}
|
||||
onValuesChange={this._valueChange}
|
||||
values={[activeIndex + 1]}
|
||||
min={1}
|
||||
max={values && values.length}
|
||||
step={1}
|
||||
allowOverlap={false}
|
||||
customMarker={this._renderMarker}
|
||||
snapped
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
19
src/components/textInput/view/textInputStyles.js
Normal file
19
src/components/textInput/view/textInputStyles.js
Normal file
@ -0,0 +1,19 @@
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
optionsWrapper: {
|
||||
backgroundColor: '$white',
|
||||
borderTopWidth: 0,
|
||||
borderColor: '$black',
|
||||
left: 0,
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
top: 50,
|
||||
zIndex: 999,
|
||||
flex: 1,
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
minHeight: 50,
|
||||
},
|
||||
});
|
@ -2,8 +2,16 @@ import React from 'react';
|
||||
import { TextInput } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
// Styles
|
||||
import styles from './textInputStyles';
|
||||
|
||||
const TextInputView = ({ isDarkTheme, innerRef, ...props }) => (
|
||||
<TextInput ref={innerRef} keyboardAppearance={isDarkTheme ? 'dark' : 'light'} {...props} />
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
ref={innerRef}
|
||||
keyboardAppearance={isDarkTheme ? 'dark' : 'light'}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
|
@ -306,5 +306,12 @@
|
||||
"incoming_funds": "Incoming Funds",
|
||||
"sc_power_down_error": "Steem connect setWithdrawVestingRoute not implemented yet.",
|
||||
"estimated_weekly": "Estimated Weekly"
|
||||
},
|
||||
"promote": {
|
||||
"title": "Promote",
|
||||
"days": "days",
|
||||
"user": "User",
|
||||
"permlink": "Permlink",
|
||||
"information": "Are you sure to transfer to promote?"
|
||||
}
|
||||
}
|
||||
|
@ -107,3 +107,24 @@ export const POINTS_KEYS = [
|
||||
type: 30,
|
||||
},
|
||||
];
|
||||
|
||||
export const PROMOTE_PRICING = [
|
||||
{ duration: 1, price: 150 },
|
||||
{ duration: 2, price: 250 },
|
||||
{ duration: 3, price: 350 },
|
||||
{ duration: 7, price: 500 },
|
||||
{ duration: 14, price: 1000 },
|
||||
];
|
||||
export const PROMOTE_DAYS = [1, 2, 3, 7, 14];
|
||||
|
||||
export const PROMOTE_STATUS_PENDING = 1;
|
||||
export const PROMOTE_STATUS_SUCCESS = 2;
|
||||
export const PROMOTE_STATUS_USER_ERR = 3;
|
||||
export const PROMOTE_STATUS_INSUFFICIENT_ERR = 4;
|
||||
export const PROMOTE_STATUS_POST_ERR = 5;
|
||||
export const PROMOTE_STATUS_POST_DUPLICATE = 6;
|
||||
export const PROMOTE_STATUS_FORMAT_ERR = 7;
|
||||
|
||||
export const PROMOTED_POST_STATUS_ON = 1;
|
||||
export const PROMOTED_POST_STATUS_EXPIRED = 2;
|
||||
export const PROMOTED_POST_STATUS_DISABLED = 3;
|
||||
|
@ -19,6 +19,7 @@ export default {
|
||||
BOOKMARKS: `Bookmarks${SCREEN_SUFFIX}`,
|
||||
SEARCH_RESULT: `SearchResult${SCREEN_SUFFIX}`,
|
||||
TRANSFER: `Transfer${SCREEN_SUFFIX}`,
|
||||
PROMOTE: `Promote${SCREEN_SUFFIX}`,
|
||||
},
|
||||
DRAWER: {
|
||||
MAIN: `Main${DRAWER_SUFFIX}`,
|
||||
|
4
src/containers/index.js
Normal file
4
src/containers/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
import PointsContainer from './pointsContainer';
|
||||
import TransferContainer from './transferContainer';
|
||||
|
||||
export { PointsContainer, TransferContainer };
|
@ -2,19 +2,21 @@ import React, { Component } from 'react';
|
||||
import { Alert } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import get from 'lodash/get';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { withNavigation } from 'react-navigation';
|
||||
|
||||
// Services and Actions
|
||||
import { getUser, getUserPoints, claim } from '../../../providers/esteem/ePoint';
|
||||
import { openPinCodeModal } from '../../../redux/actions/applicationActions';
|
||||
import { getUser, getUserPoints, claim } from '../providers/esteem/ePoint';
|
||||
import { openPinCodeModal } from '../redux/actions/applicationActions';
|
||||
import { promote, getAccount } from '../providers/steem/dsteem';
|
||||
import { getUserDataWithUsername } from '../realm/realm';
|
||||
import { toastNotification } from '../redux/actions/uiAction';
|
||||
|
||||
// Constant
|
||||
import POINTS from '../../../constants/options/points';
|
||||
|
||||
// Component
|
||||
import PointsView from '../view/pointsView';
|
||||
import POINTS from '../constants/options/points';
|
||||
|
||||
// Constants
|
||||
import ROUTES from '../../../constants/routeNames';
|
||||
import ROUTES from '../constants/routeNames';
|
||||
|
||||
/*
|
||||
* Props Name Description Value
|
||||
@ -60,18 +62,37 @@ class PointsContainer extends Component {
|
||||
|
||||
// Component Functions
|
||||
|
||||
_handleOnPressTransfer = () => {
|
||||
_handleOnPressTransfer = index => {
|
||||
const { dispatch } = this.props;
|
||||
const { userPoints } = this.state;
|
||||
const { balance } = this.state;
|
||||
let navigateTo;
|
||||
let navigateParams;
|
||||
|
||||
switch (Number(index)) {
|
||||
case 0:
|
||||
navigateTo = ROUTES.SCREENS.TRANSFER;
|
||||
navigateParams = {
|
||||
transferType: 'points',
|
||||
fundType: 'POINT',
|
||||
balance,
|
||||
};
|
||||
break;
|
||||
|
||||
case 1:
|
||||
navigateTo = ROUTES.SCREENS.PROMOTE;
|
||||
navigateParams = {
|
||||
balance,
|
||||
};
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dispatch(
|
||||
openPinCodeModal({
|
||||
navigateTo: ROUTES.SCREENS.TRANSFER,
|
||||
navigateParams: {
|
||||
transferType: 'points',
|
||||
fundType: 'POINT',
|
||||
balance: Math.round(get(userPoints, 'points') * 1000) / 1000,
|
||||
},
|
||||
navigateTo,
|
||||
navigateParams,
|
||||
}),
|
||||
);
|
||||
};
|
||||
@ -90,10 +111,11 @@ class PointsContainer extends Component {
|
||||
|
||||
await getUser(username)
|
||||
.then(userPoints => {
|
||||
this.setState({ userPoints });
|
||||
const balance = Math.round(get(userPoints, 'points') * 1000) / 1000;
|
||||
this.setState({ userPoints, balance });
|
||||
})
|
||||
.catch(err => {
|
||||
Alert.alert(err);
|
||||
Alert.alert(err.message);
|
||||
});
|
||||
|
||||
await getUserPoints(username)
|
||||
@ -114,6 +136,17 @@ class PointsContainer extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
_getUserBalance = async username => {
|
||||
await getUser(username)
|
||||
.then(userPoints => {
|
||||
const balance = Math.round(get(userPoints, 'points') * 1000) / 1000;
|
||||
return balance;
|
||||
})
|
||||
.catch(err => {
|
||||
Alert.alert(err);
|
||||
});
|
||||
};
|
||||
|
||||
_claimPoints = async () => {
|
||||
const { username } = this.props;
|
||||
|
||||
@ -135,6 +168,26 @@ class PointsContainer extends Component {
|
||||
this.setState({ isClaiming: false });
|
||||
};
|
||||
|
||||
_promote = async (duration, permlink, author, user) => {
|
||||
const { currentAccount, pinCode, dispatch, intl, navigation } = this.props;
|
||||
this.setState({ isLoading: true });
|
||||
|
||||
await promote(user || currentAccount, pinCode, duration, permlink, author)
|
||||
.then(() => {
|
||||
this.setState({ isLoading: false });
|
||||
dispatch(toastNotification(intl.formatMessage({ id: 'alert.successful' })));
|
||||
navigation.goBack();
|
||||
})
|
||||
.catch(error => {
|
||||
Alert.alert(
|
||||
`Fetching data from server failed, please try again or notify us at info@esteem.app \n${error.message.substr(
|
||||
0,
|
||||
20,
|
||||
)}`,
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
isClaiming,
|
||||
@ -143,20 +196,31 @@ class PointsContainer extends Component {
|
||||
refreshing,
|
||||
userActivities,
|
||||
userPoints,
|
||||
balance,
|
||||
} = this.state;
|
||||
const { children, accounts, currentAccount } = this.props;
|
||||
|
||||
return (
|
||||
<PointsView
|
||||
claimPoints={this._claimPoints}
|
||||
fetchUserActivity={this._fetchuserPointActivities}
|
||||
isClaiming={isClaiming}
|
||||
isDarkTheme={isDarkTheme}
|
||||
isLoading={isLoading}
|
||||
refreshing={refreshing}
|
||||
userActivities={userActivities}
|
||||
userPoints={userPoints}
|
||||
handleOnPressTransfer={this._handleOnPressTransfer}
|
||||
/>
|
||||
children &&
|
||||
children({
|
||||
accounts,
|
||||
currentAccount,
|
||||
currentAccountName: currentAccount.name,
|
||||
claimPoints: this._claimPoints,
|
||||
fetchUserActivity: this._fetchuserPointActivities,
|
||||
isClaiming,
|
||||
isDarkTheme,
|
||||
isLoading,
|
||||
refreshing,
|
||||
userActivities,
|
||||
userPoints,
|
||||
handleOnPressTransfer: this._handleOnPressTransfer,
|
||||
balance,
|
||||
getUserBalance: this._getUserBalance,
|
||||
promote: this._promote,
|
||||
getAccount,
|
||||
getUserDataWithUsername,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -165,6 +229,9 @@ const mapStateToProps = state => ({
|
||||
username: state.account.currentAccount.name,
|
||||
isDarkTheme: state.application.isDarkTheme,
|
||||
activeBottomTab: state.ui.activeBottomTab,
|
||||
accounts: state.account.otherAccounts,
|
||||
currentAccount: state.account.currentAccount,
|
||||
pinCode: state.account.pin,
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps)(PointsContainer);
|
||||
export default withNavigation(connect(mapStateToProps)(injectIntl(PointsContainer)));
|
@ -14,12 +14,12 @@ import {
|
||||
withdrawVesting,
|
||||
delegateVestingShares,
|
||||
setWithdrawVestingRoute,
|
||||
} from '../../../providers/steem/dsteem';
|
||||
import { toastNotification } from '../../../redux/actions/uiAction';
|
||||
import { getUserDataWithUsername } from '../../../realm/realm';
|
||||
} from '../providers/steem/dsteem';
|
||||
import { toastNotification } from '../redux/actions/uiAction';
|
||||
import { getUserDataWithUsername } from '../realm/realm';
|
||||
|
||||
// Utils
|
||||
import { countDecimals } from '../../../utils/number';
|
||||
import { countDecimals } from '../utils/number';
|
||||
|
||||
/*
|
||||
* Props Name Description Value
|
@ -22,6 +22,7 @@ import {
|
||||
Voters,
|
||||
SearchResult,
|
||||
Transfer,
|
||||
Promote,
|
||||
} from '../screens';
|
||||
|
||||
// Components
|
||||
@ -106,6 +107,12 @@ const stackNavigatior = createStackNavigator(
|
||||
header: () => null,
|
||||
},
|
||||
},
|
||||
[ROUTES.SCREENS.PROMOTE]: {
|
||||
screen: RootComponent()(Promote),
|
||||
navigationOptions: {
|
||||
header: () => null,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
headerMode: 'none',
|
||||
|
@ -1,12 +1,6 @@
|
||||
import { Alert } from 'react-native';
|
||||
import { Client, PrivateKey } from 'dsteem';
|
||||
import ePointApi from '../../config/ePoint';
|
||||
|
||||
// Utils
|
||||
import { decryptKey } from '../../utils/crypto';
|
||||
|
||||
// const client = new Client(getItem('server', 'https://api.steemit.com'));
|
||||
|
||||
export const userActivity = (us, ty, bl = '', tx = '') =>
|
||||
new Promise(resolve => {
|
||||
const params = { us, ty };
|
||||
|
@ -226,6 +226,20 @@ export const search = data =>
|
||||
});
|
||||
});
|
||||
|
||||
export const searchPath = q =>
|
||||
new Promise((resolve, reject) => {
|
||||
searchApi
|
||||
.post('/search-path', {
|
||||
q,
|
||||
})
|
||||
.then(res => {
|
||||
resolve(res.data);
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
// Schedule
|
||||
export const schedule = (
|
||||
user,
|
||||
|
@ -1108,6 +1108,60 @@ export const transferPoint = (currentAccount, pinCode, data) => {
|
||||
return Promise.reject(new Error('Something went wrong!'));
|
||||
};
|
||||
|
||||
export const promote = (currentAccount, pinCode, duration, permlink, author) => {
|
||||
const pin = getDigitPinCode(pinCode);
|
||||
const key = getActiveKey(get(currentAccount, 'local'), pin);
|
||||
|
||||
if (key) {
|
||||
const privateKey = PrivateKey.fromString(key);
|
||||
const user = get(currentAccount, 'name');
|
||||
|
||||
const json = {
|
||||
id: 'esteem_promote',
|
||||
json: JSON.stringify({
|
||||
user,
|
||||
author,
|
||||
permlink,
|
||||
duration,
|
||||
}),
|
||||
required_auths: [user],
|
||||
required_posting_auths: [],
|
||||
};
|
||||
|
||||
return client.broadcast.json(json, privateKey);
|
||||
}
|
||||
|
||||
return Promise.reject(new Error('Something went wrong!'));
|
||||
};
|
||||
|
||||
export const boost = (currentAccount, pinCode, point, permlink, author) => {
|
||||
const pin = getDigitPinCode(pinCode);
|
||||
const key = getActiveKey(get(currentAccount, 'local'), pin);
|
||||
|
||||
if (key) {
|
||||
const privateKey = PrivateKey.fromString(key);
|
||||
const user = get(currentAccount, 'name');
|
||||
|
||||
const json = {
|
||||
id: 'esteem_boost',
|
||||
json: JSON.stringify({
|
||||
user,
|
||||
author,
|
||||
permlink,
|
||||
amount: `${point} POINT`,
|
||||
}),
|
||||
required_auths: [user],
|
||||
required_posting_auths: [],
|
||||
};
|
||||
|
||||
return client.broadcast.json(json, privateKey);
|
||||
}
|
||||
|
||||
return Promise.reject(new Error('Something went wrong!'));
|
||||
};
|
||||
|
||||
// HELPERS
|
||||
|
||||
const getAnyPrivateKey = (local, pin) => {
|
||||
const { postingKey, activeKey } = local;
|
||||
|
||||
|
@ -16,6 +16,7 @@ import RootComponent from './root';
|
||||
import SteemConnect from './steem-connect/steemConnect';
|
||||
import { SearchResult } from './searchResult';
|
||||
import Transfer from './transfer';
|
||||
import Promote from './promote/screen/promoteScreen';
|
||||
|
||||
export {
|
||||
Bookmarks,
|
||||
@ -25,15 +26,16 @@ export {
|
||||
Home,
|
||||
Launch,
|
||||
Login,
|
||||
Points,
|
||||
Notification,
|
||||
PinCode,
|
||||
Points,
|
||||
Post,
|
||||
Profile,
|
||||
Promote,
|
||||
RootComponent,
|
||||
SearchResult,
|
||||
Settings,
|
||||
SteemConnect,
|
||||
Voters,
|
||||
SearchResult,
|
||||
Transfer,
|
||||
Voters,
|
||||
};
|
||||
|
@ -1,7 +1,9 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { View } from 'react-native';
|
||||
// Constants
|
||||
|
||||
// Containers
|
||||
import { PointsContainer } from '../../../containers';
|
||||
|
||||
// Components
|
||||
import { Header } from '../../../components/header';
|
||||
@ -33,7 +35,31 @@ class PointsScreen extends PureComponent {
|
||||
<View style={styles.container}>
|
||||
<Header />
|
||||
{isLoggedIn ? (
|
||||
<Points />
|
||||
<PointsContainer>
|
||||
{({
|
||||
handleOnPressTransfer,
|
||||
claimPoints,
|
||||
fetchUserActivity,
|
||||
isClaiming,
|
||||
isDarkTheme,
|
||||
isLoading,
|
||||
refreshing,
|
||||
userActivities,
|
||||
userPoints,
|
||||
}) => (
|
||||
<Points
|
||||
claimPoints={claimPoints}
|
||||
fetchUserActivity={fetchUserActivity}
|
||||
isClaiming={isClaiming}
|
||||
isDarkTheme={isDarkTheme}
|
||||
isLoading={isLoading}
|
||||
refreshing={refreshing}
|
||||
userActivities={userActivities}
|
||||
userPoints={userPoints}
|
||||
handleOnPressTransfer={handleOnPressTransfer}
|
||||
/>
|
||||
)}
|
||||
</PointsContainer>
|
||||
) : (
|
||||
<NoPost
|
||||
style={styles.noPostContainer}
|
||||
|
282
src/screens/promote/screen/promoteScreen.js
Normal file
282
src/screens/promote/screen/promoteScreen.js
Normal file
@ -0,0 +1,282 @@
|
||||
import React, { PureComponent, Fragment } from 'react';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { Text, View, WebView, ScrollView, TouchableOpacity, Alert } from 'react-native';
|
||||
import get from 'lodash/get';
|
||||
import ActionSheet from 'react-native-actionsheet';
|
||||
import Autocomplete from 'react-native-autocomplete-input';
|
||||
import { ScaleSlider, TextInput } from '../../../components';
|
||||
import { steemConnectOptions } from '../../../constants/steemConnectOptions';
|
||||
|
||||
// Container
|
||||
import { PointsContainer } from '../../../containers';
|
||||
|
||||
// Services and Actions
|
||||
import { getUser } from '../../../providers/esteem/ePoint';
|
||||
import { searchPath } from '../../../providers/esteem/esteem';
|
||||
|
||||
// Components
|
||||
import { BasicHeader } from '../../../components/basicHeader';
|
||||
import { TransferFormItem } from '../../../components/transferFormItem';
|
||||
import { MainButton } from '../../../components/mainButton';
|
||||
import { DropdownButton } from '../../../components/dropdownButton';
|
||||
import { Modal } from '../../../components/modal';
|
||||
|
||||
import { PROMOTE_PRICING, PROMOTE_DAYS } from '../../../constants/options/points';
|
||||
|
||||
// Styles
|
||||
import styles from './promoteStyles';
|
||||
|
||||
class PointsScreen extends PureComponent {
|
||||
/* Props
|
||||
* ------------------------------------------------
|
||||
* @prop { type } name - Description....
|
||||
*/
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
permlink: '',
|
||||
selectedUser: '',
|
||||
balance: '',
|
||||
day: 1,
|
||||
isSCModalOpen: false,
|
||||
SCPath: '',
|
||||
permlinkSuggestions: [],
|
||||
};
|
||||
|
||||
this.startActionSheet = React.createRef();
|
||||
}
|
||||
|
||||
// Component Life Cycles
|
||||
|
||||
// Component Functions
|
||||
|
||||
_handleOnPermlinkChange = async text => {
|
||||
searchPath(text).then(res => {
|
||||
this.setState({ permlinkSuggestions: res && res.length > 10 ? res.slice(0, 7) : res });
|
||||
});
|
||||
|
||||
if (!text || (text && text.length < 1)) this.setState({ permlinkSuggestions: [] });
|
||||
|
||||
this.setState({ permlink: text });
|
||||
};
|
||||
|
||||
_renderDescription = text => <Text style={styles.description}>{text}</Text>;
|
||||
|
||||
_renderDropdown = (accounts, currentAccountName) => (
|
||||
<DropdownButton
|
||||
dropdownButtonStyle={styles.dropdownButtonStyle}
|
||||
rowTextStyle={styles.rowTextStyle}
|
||||
style={styles.dropdown}
|
||||
dropdownStyle={styles.dropdownStyle}
|
||||
textStyle={styles.dropdownText}
|
||||
options={accounts.map(item => item.username)}
|
||||
defaultText={currentAccountName}
|
||||
selectedOptionIndex={accounts.findIndex(item => item.username === currentAccountName)}
|
||||
onSelect={(index, value) => {
|
||||
this.setState({ selectedUser: value });
|
||||
this._getUserBalance(value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
_getUserBalance = async username => {
|
||||
await getUser(username)
|
||||
.then(userPoints => {
|
||||
const balance = Math.round(get(userPoints, 'points') * 1000) / 1000;
|
||||
this.setState({ balance });
|
||||
})
|
||||
.catch(err => {
|
||||
Alert.alert(err);
|
||||
});
|
||||
};
|
||||
|
||||
_promote = async (promote, currentAccount, getUserDataWithUsername) => {
|
||||
const { day, permlink, selectedUser } = this.state;
|
||||
let _author;
|
||||
let _permlink;
|
||||
|
||||
const seperatedPermlink = permlink.split('/');
|
||||
if (seperatedPermlink && seperatedPermlink.length > 0) {
|
||||
_author = seperatedPermlink[0];
|
||||
_permlink = seperatedPermlink[1];
|
||||
}
|
||||
|
||||
if (get(currentAccount, 'local.authType') === 'steemConnect') {
|
||||
// const user = selectedUser;
|
||||
|
||||
const json = JSON.stringify({
|
||||
user: selectedUser,
|
||||
_author,
|
||||
_permlink,
|
||||
duration: day,
|
||||
});
|
||||
|
||||
const uri = `sign/custom-json?authority=active&required_auths=%5B%22${selectedUser}%22%5D&required_posting_auths=%5B%5D&id=esteem_promote&json=${encodeURIComponent(
|
||||
json,
|
||||
)}`;
|
||||
|
||||
this.setState({
|
||||
isSCModalOpen: true,
|
||||
SCPath: uri,
|
||||
});
|
||||
} else if (promote) {
|
||||
let userFromRealm;
|
||||
|
||||
if (selectedUser) {
|
||||
userFromRealm = await getUserDataWithUsername(selectedUser);
|
||||
}
|
||||
|
||||
const user = userFromRealm
|
||||
? {
|
||||
name: selectedUser,
|
||||
local: userFromRealm[0],
|
||||
}
|
||||
: currentAccount;
|
||||
|
||||
promote(day, _permlink, _author, user);
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { intl } = this.props;
|
||||
const {
|
||||
selectedUser,
|
||||
balance,
|
||||
day,
|
||||
SCPath,
|
||||
isSCModalOpen,
|
||||
permlinkSuggestions,
|
||||
permlink,
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<PointsContainer>
|
||||
{({
|
||||
isLoading,
|
||||
accounts,
|
||||
currentAccountName,
|
||||
balance: _balance,
|
||||
promote,
|
||||
currentAccount,
|
||||
getUserDataWithUsername,
|
||||
}) => (
|
||||
<Fragment>
|
||||
<BasicHeader title={intl.formatMessage({ id: 'promote.title' })} />
|
||||
<View style={styles.container}>
|
||||
<ScrollView>
|
||||
<View style={styles.middleContent}>
|
||||
<TransferFormItem
|
||||
label={intl.formatMessage({ id: 'promote.user' })}
|
||||
rightComponent={() =>
|
||||
this._renderDropdown(accounts, selectedUser || currentAccountName)
|
||||
}
|
||||
/>
|
||||
<Text style={styles.balanceText}>{`${balance || _balance} eSteem Points`}</Text>
|
||||
<Fragment>
|
||||
<View style={styles.autocomplateLineContainer}>
|
||||
<View style={styles.autocomplateLabelContainer}>
|
||||
{
|
||||
<Text style={styles.autocomplateLabelText}>
|
||||
{intl.formatMessage({ id: 'promote.permlink' })}
|
||||
</Text>
|
||||
}
|
||||
</View>
|
||||
|
||||
<Autocomplete
|
||||
autoCapitalize="none"
|
||||
autoCorrect={false}
|
||||
inputContainerStyle={styles.autocomplate}
|
||||
data={permlinkSuggestions}
|
||||
listContainerStyle={styles.autocomplateListContainer}
|
||||
listStyle={styles.autocomplateList}
|
||||
onChangeText={text => this._handleOnPermlinkChange(text)}
|
||||
renderTextInput={() => (
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
onChangeText={text => this._handleOnPermlinkChange(text)}
|
||||
value={permlink}
|
||||
placeholder={intl.formatMessage({ id: 'promote.permlink' })}
|
||||
placeholderTextColor="#c1c5c7"
|
||||
autoCapitalize="none"
|
||||
/>
|
||||
)}
|
||||
renderItem={({ item }) => (
|
||||
<TouchableOpacity
|
||||
key={item}
|
||||
onPress={() =>
|
||||
this.setState({ permlink: item, permlinkSuggestions: [] })
|
||||
}
|
||||
>
|
||||
<Text style={styles.autocomplateItemText}>{item}</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</Fragment>
|
||||
|
||||
<View style={styles.total}>
|
||||
<Text style={styles.day}>
|
||||
{`${day} ${intl.formatMessage({
|
||||
id: 'promote.days',
|
||||
})} `}
|
||||
</Text>
|
||||
<Text style={styles.price}>
|
||||
{`${get(PROMOTE_PRICING[PROMOTE_DAYS.indexOf(day)], 'price')} eSteem points`}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<ScaleSlider
|
||||
values={[1, 2, 3, 7, 14]}
|
||||
LRpadding={50}
|
||||
activeValue={day}
|
||||
handleOnValueChange={day => this.setState({ day })}
|
||||
single
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.bottomContent}>
|
||||
<MainButton
|
||||
style={styles.button}
|
||||
isDisable={isLoading}
|
||||
onPress={() => this.startActionSheet.current.show()}
|
||||
isLoading={isLoading}
|
||||
>
|
||||
<Text style={styles.buttonText}>
|
||||
{intl.formatMessage({ id: 'transfer.next' })}
|
||||
</Text>
|
||||
</MainButton>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</View>
|
||||
<ActionSheet
|
||||
ref={this.startActionSheet}
|
||||
options={[
|
||||
intl.formatMessage({ id: 'alert.confirm' }),
|
||||
intl.formatMessage({ id: 'alert.cancel' }),
|
||||
]}
|
||||
title={intl.formatMessage({ id: 'promote.information' })}
|
||||
cancelButtonIndex={1}
|
||||
destructiveButtonIndex={0}
|
||||
onPress={index => {
|
||||
index === 0
|
||||
? this._promote(promote, currentAccount, getUserDataWithUsername)
|
||||
: null;
|
||||
}}
|
||||
/>
|
||||
<Modal
|
||||
isOpen={isSCModalOpen}
|
||||
isFullScreen
|
||||
isCloseButton
|
||||
handleOnModalClose={() => this.setState({ isSCModalOpen: false })}
|
||||
title={intl.formatMessage({ id: 'transfer.steemconnect_title' })}
|
||||
>
|
||||
<WebView source={{ uri: `${steemConnectOptions.base_url}${SCPath}` }} />
|
||||
</Modal>
|
||||
</Fragment>
|
||||
)}
|
||||
</PointsContainer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(PointsScreen);
|
162
src/screens/promote/screen/promoteStyles.js
Normal file
162
src/screens/promote/screen/promoteStyles.js
Normal file
@ -0,0 +1,162 @@
|
||||
import EStyleSheet from 'react-native-extended-stylesheet';
|
||||
|
||||
export default EStyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '$primaryBackgroundColor',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
balanceText: {
|
||||
fontSize: 14,
|
||||
color: '$primaryDarkGray',
|
||||
alignSelf: 'center',
|
||||
marginLeft: 70,
|
||||
marginBottom: 10,
|
||||
},
|
||||
topContent: {
|
||||
flexDirection: 'row',
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
middleContent: {
|
||||
flex: 3,
|
||||
justifyContent: 'center',
|
||||
},
|
||||
bottomContent: {
|
||||
flex: 2,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: -1,
|
||||
},
|
||||
input: {
|
||||
borderWidth: 1,
|
||||
borderColor: '$borderColor',
|
||||
borderRadius: 8,
|
||||
padding: 10,
|
||||
color: '$primaryBlack',
|
||||
width: 172,
|
||||
},
|
||||
autocomplate: {
|
||||
borderWidth: 0,
|
||||
borderColor: '$borderColor',
|
||||
borderRadius: 8,
|
||||
padding: 2,
|
||||
color: '$primaryBlack',
|
||||
width: 172,
|
||||
marginRight: 33,
|
||||
},
|
||||
autocomplateLineContainer: {
|
||||
flexDirection: 'row',
|
||||
paddingHorizontal: 20,
|
||||
zIndex: 999,
|
||||
},
|
||||
autocomplateLabelText: {
|
||||
color: '$primaryBlack',
|
||||
fontWeight: '600',
|
||||
},
|
||||
autocomplateListContainer: {
|
||||
backgroundColor: '$primaryWhiteLightBackground',
|
||||
width: 172,
|
||||
zIndex: 999,
|
||||
},
|
||||
autocomplateItemText: {
|
||||
color: '$primaryBlack',
|
||||
padding: 3,
|
||||
},
|
||||
autocomplateList: {
|
||||
zIndex: 999,
|
||||
backgroundColor: '$primaryWhiteLightBackground',
|
||||
},
|
||||
autocomplateLabelContainer: {
|
||||
flex: 1,
|
||||
padding: 10,
|
||||
justifyContent: 'center',
|
||||
color: '$primaryBlack',
|
||||
},
|
||||
textarea: {
|
||||
borderWidth: 1,
|
||||
borderColor: '$borderColor',
|
||||
borderRadius: 8,
|
||||
padding: 10,
|
||||
color: '$primaryBlack',
|
||||
width: 172,
|
||||
height: 75,
|
||||
},
|
||||
description: {
|
||||
color: '$iconColor',
|
||||
},
|
||||
button: {
|
||||
width: '$deviceWidth / 3',
|
||||
marginTop: 30,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
buttonText: {
|
||||
color: 'white',
|
||||
},
|
||||
icon: {
|
||||
fontSize: 40,
|
||||
color: '$iconColor',
|
||||
marginHorizontal: 20,
|
||||
},
|
||||
rowTextStyle: {
|
||||
fontSize: 12,
|
||||
color: '$primaryDarkGray',
|
||||
padding: 5,
|
||||
},
|
||||
dropdownText: {
|
||||
fontSize: 14,
|
||||
paddingLeft: 16,
|
||||
paddingHorizontal: 14,
|
||||
color: '$primaryDarkGray',
|
||||
},
|
||||
dropdownStyle: {
|
||||
marginTop: 15,
|
||||
minWidth: 192,
|
||||
width: 192,
|
||||
maxHeight: '$deviceHeight - 200',
|
||||
},
|
||||
dropdownButtonStyle: {
|
||||
borderColor: '$borderColor',
|
||||
borderWidth: 1,
|
||||
height: 44,
|
||||
width: 172,
|
||||
borderRadius: 8,
|
||||
marginHorizontal: 2,
|
||||
},
|
||||
dropdown: {
|
||||
flexGrow: 1,
|
||||
width: 150,
|
||||
},
|
||||
slider: {
|
||||
flex: 1,
|
||||
marginHorizontal: 30,
|
||||
},
|
||||
amountText: {
|
||||
color: '$primaryBlue',
|
||||
},
|
||||
iconButton: {
|
||||
borderColor: 'red',
|
||||
borderWidth: 1,
|
||||
width: 25,
|
||||
height: 25,
|
||||
borderRadius: 5,
|
||||
},
|
||||
total: {
|
||||
marginVertical: 15,
|
||||
flexDirection: 'row',
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
day: {
|
||||
fontSize: 22,
|
||||
color: '$primaryBlue',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
price: {
|
||||
fontSize: 15,
|
||||
color: '$primaryBlue',
|
||||
},
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import TransferContainer from './container/transferContainer';
|
||||
import { TransferContainer } from '../../containers';
|
||||
|
||||
import TransferView from './screen/transferScreen';
|
||||
import PowerDownView from './screen/powerDownScreen';
|
||||
|
@ -16,6 +16,7 @@ import { Icon } from '../../../components/icon';
|
||||
import { Modal } from '../../../components/modal';
|
||||
|
||||
import styles from './transferStyles';
|
||||
|
||||
/* Props
|
||||
* ------------------------------------------------
|
||||
* @prop { type } name - Description....
|
||||
|
10
yarn.lock
10
yarn.lock
@ -1256,6 +1256,11 @@
|
||||
"@types/istanbul-reports" "^1.1.1"
|
||||
"@types/yargs" "^12.0.9"
|
||||
|
||||
"@ptomasroos/react-native-multi-slider@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@ptomasroos/react-native-multi-slider/-/react-native-multi-slider-1.0.0.tgz#a4ea27b1320b93a1db9f696c24789695df6c9f30"
|
||||
integrity sha512-NpX22rQLArg9widwMzGf7XsInTDf6mfY/D1XaDVjglNkVphj3NSN37+nF6MofArCxC++1P+jHv0SGWbmJQwy4g==
|
||||
|
||||
"@react-native-community/cli@^1.2.1":
|
||||
version "1.9.11"
|
||||
resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-1.9.11.tgz#b868b17201057b9cd16a3a20c30561176071f21a"
|
||||
@ -7487,6 +7492,11 @@ react-native-actionsheet@^2.4.2:
|
||||
resolved "https://registry.yarnpkg.com/react-native-actionsheet/-/react-native-actionsheet-2.4.2.tgz#6a00dd51a75ef2c8974312130e405af73191500f"
|
||||
integrity sha512-DBoWIvVwuWXuptF4t46pBqkFxaUxS+rsIdHiA05t0n4BdTIDV2R4s9bLEUVOGzb94D7VxIamsXZPA/3mmw+SXg==
|
||||
|
||||
react-native-autocomplete-input@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-native-autocomplete-input/-/react-native-autocomplete-input-4.1.0.tgz#979ece28d891b245ecb967b6d31f1f924445b8ab"
|
||||
integrity sha512-Yn4GulZ9F6tde74UUGZHdVFeYWVuL7+EbUZy6kt+QHrzMc5B4OuRop1FT4RyWLpvbySW/vvqYgj9LAmlzkuEqA==
|
||||
|
||||
react-native-code-push@esteemapp/react-native-code-push:
|
||||
version "1000.0.0-beta"
|
||||
resolved "https://codeload.github.com/esteemapp/react-native-code-push/tar.gz/c07b7023c1212dc5d9231a0526a869d2501cb221"
|
||||
|
Loading…
Reference in New Issue
Block a user