Advertisement
Guest User

Untitled

a guest
Jul 29th, 2017
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.53 KB | None | 0 0
  1. import React, { Component, PropTypes } from 'react';
  2. import {
  3. View,
  4. StyleSheet,
  5. Image,
  6. Text,
  7. StatusBar,
  8. Animated,
  9. ActivityIndicator,
  10. ToolbarAndroid,
  11. TouchableNativeFeedback,
  12. TouchableWithoutFeedback,
  13. } from 'react-native';
  14. import Modal from 'react-native-modal';
  15. import { connect } from 'react-redux';
  16. import moment from 'moment';
  17. import Item from './Item';
  18. import * as constants from './utils/constants';
  19. import TransactionsModal from './modals/TransactionsModal';
  20. import Fab from './shared/Fab';
  21. import * as actions from '../../actions/index';
  22.  
  23. const HEADER_MAX_HEIGHT = 160;
  24. const DELTA = 20;
  25. const TOOLBAR_HEIGHT = 56;
  26. const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - TOOLBAR_HEIGHT;
  27.  
  28. const ic_close_black = require('../../assets/icons/ic_close_black.png');
  29. const ic_incoming_transaction = require('../../assets/icons/ic_incoming.png');
  30. const ic_outgoing_transaction = require('../../assets/icons/ic_payment.png');
  31. const ic_back_white = require('../../assets/icons/ic_back_white.png');
  32. const ic_settings_white = require('../../assets/icons/ic_settings_white.png');
  33. const ic_fab = require('../../assets/icons/ic_fab_money.png');
  34. const ic_empty = require('../../assets/icons/ic_profile_feed.png');
  35.  
  36. export class Profile extends Component {
  37. static propTypes = {
  38. navigation: PropTypes.shape({
  39. navigate: PropTypes.func.isRequired,
  40. dispatch: PropTypes.func.isRequired,
  41. }),
  42. };
  43. offset = 0
  44. limit = 10
  45. activity = true
  46. constructor(props) {
  47. super(props);
  48. this.state = {
  49. scrollY: new Animated.Value(0),
  50. modalVisibility: false,
  51. newTransactionModalVisibility: false,
  52. item: {},
  53. // TODO get user from props (redux)
  54. user: {
  55. id: '1568161709003113564',
  56. pic: 'http://www.gstatic.com/webp/gallery/2.jpg',
  57. balance: {
  58. token: {
  59. currency: '',
  60. amount: '',
  61. },
  62. price: {
  63. currency: '',
  64. amount: '',
  65. },
  66. },
  67. name: 'User',
  68. surname: 'User1',
  69. phone: '+1 (234) 567-8901',
  70. status: 1, // 1 - online, 0 - offline
  71. password: 'djamik123',
  72. wallet: '0x123123123123',
  73. },
  74. transactions: [],
  75. showFooter: false,
  76. arrayChanged: true,
  77. loading: false,
  78. refreshing: false,
  79. };
  80. }
  81.  
  82. componentWillMount() {
  83.  
  84. }
  85.  
  86.  
  87. componentDidMount() {
  88.  
  89. }
  90.  
  91.  
  92. // animation in order to make collapse effects
  93. getAnimationType = (type) => {
  94. switch (type) {
  95. case constants.HEADER_TRANSLATE:
  96. return this.state.scrollY.interpolate({
  97. inputRange: [0, HEADER_SCROLL_DISTANCE],
  98. outputRange: [0, -HEADER_SCROLL_DISTANCE],
  99. extrapolate: 'clamp',
  100. });
  101. case constants.HEADER_TRANSLATE2:
  102. return this.state.scrollY.interpolate({
  103. inputRange: [0, HEADER_SCROLL_DISTANCE],
  104. outputRange: [0, HEADER_SCROLL_DISTANCE],
  105. extrapolate: 'clamp',
  106. });
  107. case constants.VIEW_TRANSLATE:
  108. return this.state.scrollY.interpolate({
  109. inputRange: [0, HEADER_SCROLL_DISTANCE],
  110. outputRange: [1, 0.7],
  111. extrapolate: 'clamp',
  112. });
  113. case constants.VIEWY_TRANSLATE:
  114. return this.state.scrollY.interpolate({
  115. inputRange: [0, HEADER_SCROLL_DISTANCE],
  116. outputRange: [0, DELTA + (0.7 * DELTA)],
  117. extrapolate: 'clamp',
  118. });
  119. case constants.IMAGE_OPACITY:
  120. return this.state.scrollY.interpolate({
  121. inputRange: [0, HEADER_SCROLL_DISTANCE / 2],
  122. outputRange: [1, 0],
  123. extrapolate: 'clamp',
  124. });
  125. default:
  126. return '';
  127. }
  128. };
  129.  
  130. render() {
  131. const { user } = this.state;
  132. const { profile } = this.props;
  133. // break amount into two values to use them separately
  134. const hmqInt = user && user.balance && user.balance.token && user.balance.token.amount
  135. ? user.balance.token.amount.toString().split('.')[0] : '0';
  136. const hmqDec = user && user.balance && user.balance.token && user.balance.token.amount
  137. ? user.balance.token.amount.toString().split('.')[1] : '00';
  138. // break amount into two values to use them separately
  139. const currencyInt = user && user.balance && user.balance.price && user.balance.price.amount
  140. ? user.balance.price.amount.toString().split('.')[0] : '0';
  141. const currencyDec = user && user.balance && user.balance.price && user.balance.price.amount
  142. ? user.balance.price.amount.toString().split('.')[1] : '00';
  143.  
  144. return (
  145. <View style={styles.mainContainer}>
  146. {/* render status bar */}
  147. <StatusBar
  148. backgroundColor="#598FBA"
  149. />
  150. {/* render list */}
  151. {this.state.transactions.length > 0 ? this.renderContent() : this.renderEmptyView()}
  152. {/* render collapse layout */}
  153. <Animated.View
  154. style={[styles.collapseContainer, {
  155. transform: [{ translateY: this.getAnimationType(constants.HEADER_TRANSLATE) }],
  156. }]}
  157. >
  158. <Animated.View
  159. style={[styles.bar, {
  160. transform: [
  161. { scale: this.getAnimationType(constants.VIEW_TRANSLATE) },
  162. { translateY: this.getAnimationType(constants.VIEWY_TRANSLATE) },
  163. ],
  164. }]}
  165. >
  166. <Animated.View
  167. style={styles.avatarInfoContainer}
  168. >
  169. <Animated.Image
  170. style={styles.avatar}
  171. source={{ uri: profile.avatar ? profile.avatar.url : this.state.user.pic }}
  172. />
  173. <Animated.View style={styles.infoContainer}>
  174. <Text style={styles.title}>{`${hmqInt}.`}
  175. <Text style={{ fontSize: 17.5, color: '#DAE5EE' }}>
  176. {hmqDec || '00'} {user.balance.token.currency}
  177. </Text>
  178. </Text>
  179. <Text style={{ fontSize: 16, color: '#DAE5EE', marginTop: 3 }}>
  180. {`${currencyInt}.`}{currencyDec || '00'} {user.balance.price.currency}
  181. </Text>
  182. </Animated.View>
  183. </Animated.View>
  184. </Animated.View>
  185. {/* render toolbar */}
  186. <Animated.View style={[{
  187. transform: [{ translateY: this.getAnimationType(constants.HEADER_TRANSLATE2) }],
  188. }]}
  189. >
  190. <ToolbarAndroid
  191. onActionSelected={position => this.onActionClick(position)}
  192. style={styles.toolbar}
  193. onIconClicked={() => this.backButtonHandle()}
  194. navIcon={ic_back_white}
  195. actions={[{
  196. title: '',
  197. icon: ic_settings_white,
  198. show: 'always',
  199. }]}
  200. />
  201. </Animated.View>
  202. </Animated.View>
  203.  
  204.  
  205. </View>
  206. );
  207. }
  208.  
  209. backButtonHandle = () => {
  210. };
  211.  
  212. renderHeaderSection = header => (
  213. <Text style={styles.headerSection}>{header}</Text>
  214. );
  215.  
  216. // render list
  217. renderScrollViewContent = () => {
  218. // convert array to map
  219. let index = 0;
  220. const categoryMap = {};
  221. const headerIds = [];
  222. this.state.transactions.forEach((item) => {
  223. // sort by category (timestamp)
  224. const category = moment.unix(item.timestamp).format('DD.MM.YYYY').toString();
  225. if (!categoryMap[category]) {
  226. categoryMap[category] = [];
  227. headerIds[index] = category;
  228. index += 1;
  229. }
  230. categoryMap[category].push(item);
  231. });
  232.  
  233. return (
  234. <View style={styles.scrollViewContent}>
  235. {headerIds.map(item => categoryMap[item].map((child, childIndex) => (
  236. <View>
  237. {/* render header text */}
  238. {childIndex === 0 ? this.renderHeaderSection(item) : null}
  239. {/* render transaction item */}
  240. <Item
  241. item={child}
  242. currentIndex={childIndex}
  243. size={categoryMap[item].length}
  244. onClick={() => this.onItemClick(child)}
  245. />
  246. </View>
  247. )))}
  248. {this.state.showFooter ? this.progressIndicator() : null}
  249. </View>
  250. );
  251. };
  252.  
  253. _onRefresh() {
  254. this.setState({ refreshing: true });
  255. }
  256.  
  257. progressIndicator = () => (
  258. <Animated.View style={{ padding: 5 }}>
  259. <ActivityIndicator
  260. size={30}
  261. />
  262. </Animated.View>
  263. );
  264.  
  265. settingsButtonHandle = () => {
  266. const navState = this.props.navigation.state;
  267. this.props.navigation.navigate('ProfileSettings', { ...navState.params, user: this.state.user });
  268. };
  269.  
  270. // on fab button click handler
  271. onFabButtonPress = () => {
  272. // show newTransactionModal
  273. this.setState({ newTransactionModalVisibility: true });
  274. };
  275.  
  276. renderContent = () => (
  277. <Animated.ScrollView
  278. ref="scrollRef"
  279. style={{ backgroundColor: '#fff' }}
  280. scrollEventThrottle={15}
  281. onScroll={this.onScroll.bind(this)}
  282. >
  283. {this.renderScrollViewContent()}
  284. </Animated.ScrollView>
  285. );
  286.  
  287. isCloseToBottom = ({ layoutMeasurement, contentOffset, contentSize }) => {
  288. let paddingToBottom = 0;
  289. paddingToBottom += layoutMeasurement.height;
  290. return contentOffset.y >= contentSize.height - paddingToBottom;
  291. };
  292.  
  293. // combining two onScroll events (Animated.Event and onScroll event)
  294. onScroll(event) {
  295. if (this.props.onScroll) this.props.onScroll(event);
  296. Animated.event(
  297. [{ nativeEvent: { contentOffset: { y: this.state.scrollY } } }],
  298. { onScroll: this.props.onScroll }, { useNativeDriver: true },
  299. )(event);
  300. // detect if scroll reached the end of the list to load more data
  301. if (this.isCloseToBottom(event.nativeEvent)
  302. && !this.state.showFooter && this.state.arrayChanged) {
  303. this.scrollToPosition = event.nativeEvent.contentSize.height;
  304. this.setState({ showFooter: true });
  305. setTimeout(() => {
  306. if (this.activity && this.refs.scrollRef) {
  307. this.refs.scrollRef._component.scrollTo({ x: 0, y: this.scrollToPosition });
  308. this.loadMoreData();
  309. }
  310. }, 50);
  311. }
  312. }
  313. // render Empty View, if array is empty
  314. renderEmptyView = () => (
  315. <View style={styles.emptyViewContainer}>
  316. <Image
  317. resizeMode="contain"
  318. style={styles.emptyImage}
  319. source={ic_empty}
  320. />
  321. </View>
  322. );
  323.  
  324. // on transaction item click handler
  325. onItemClick = (item) => {
  326. this.setState({
  327. item,
  328. modalVisibility: true,
  329. });
  330. };
  331.  
  332. // on chat icon click handler
  333. onChatClick = () => {
  334. this.setState({
  335. modalVisibility: false,
  336. });
  337. };
  338.  
  339.  
  340. // to load more data
  341. loadMoreData() {
  342. this.getTransactions();
  343. }
  344.  
  345. componentWillUnmount() {
  346. // to prevent null pointers
  347. this.activity = false;
  348. // DeviceEventEmitter.removeAllListeners()
  349. }
  350.  
  351. // toolbar action click handler
  352. onActionClick = (position) => {
  353. switch (position) {
  354. case 0:
  355. return this.settingsButtonHandle();
  356. default:
  357. return '';
  358. }
  359. };
  360.  
  361. onRefresh() {
  362. // when pull to refresh triggers
  363. this.setState({ loading: true });
  364. setTimeout(() => this.setState({ loading: false }));
  365. }
  366.  
  367.  
  368. dismissModal() {
  369. this.setState({ newTransactionModalVisibility: false });
  370. }
  371. }
  372.  
  373. const styles = StyleSheet.create({
  374. mainContainer: {
  375. flex: 1,
  376. },
  377. collapseContainer: {
  378. position: 'absolute',
  379. top: 0,
  380. left: 0,
  381. right: 0,
  382. backgroundColor: '#598fba',
  383. overflow: 'hidden',
  384. height: HEADER_MAX_HEIGHT,
  385. },
  386. avatarInfoContainer: {
  387. flexDirection: 'row',
  388. alignItems: 'center',
  389. alignSelf: 'flex-start',
  390. marginLeft: 16,
  391. },
  392. avatar: {
  393. height: 60,
  394. width: 60,
  395. borderRadius: 65,
  396. },
  397. infoContainer: { marginLeft: 13 },
  398. bar: {
  399. backgroundColor: 'transparent',
  400. justifyContent: 'center',
  401. alignSelf: 'flex-end',
  402. position: 'absolute',
  403. left: 0,
  404. right: 0,
  405. bottom: DELTA,
  406. },
  407. title: {
  408. color: 'white',
  409. fontSize: 28,
  410. },
  411. scrollViewContent: {
  412. marginTop: HEADER_MAX_HEIGHT,
  413. backgroundColor: '#fff',
  414. },
  415. backButton: {
  416. marginLeft: 16,
  417. },
  418. settingsButton: {
  419. marginRight: 16,
  420. },
  421. headerSection: {
  422. marginLeft: 16.5,
  423. marginTop: 33,
  424. marginBottom: 13,
  425. color: '#2586C6',
  426. fontSize: 16.5,
  427. fontWeight: '500',
  428. },
  429. back: {
  430. height: 24,
  431. width: 24,
  432. },
  433. settings: {
  434. height: 24,
  435. width: 24,
  436. },
  437. toolbar: {
  438. height: TOOLBAR_HEIGHT,
  439. backgroundColor: 'transparent',
  440. },
  441. emptyViewContainer: {
  442. marginTop: HEADER_MAX_HEIGHT,
  443. flex: 1,
  444. backgroundColor: '#fff',
  445. alignItems: 'center',
  446. justifyContent: 'center',
  447. },
  448. emptyImage: {},
  449. priceInt: {
  450. fontSize: 16,
  451. color: '#000000',
  452. },
  453. priceDecimal: {
  454. color: '#8B8B8B',
  455. fontSize: 14,
  456. },
  457.  
  458. rootContainer: {
  459. justifyContent: 'flex-end',
  460. flex: 1,
  461. },
  462. content: {
  463. backgroundColor: '#ffffff',
  464. height: 250,
  465. justifyContent: 'flex-end',
  466. },
  467. closeButtonContainer: {
  468. padding: 15,
  469. alignItems: 'center',
  470. },
  471. imageContainer: {
  472. flexDirection: 'row',
  473. flex: 1,
  474. },
  475. transactionImageContainer: {
  476. padding: 10,
  477. flex: 1,
  478. alignItems: 'center',
  479. justifyContent: 'center',
  480. },
  481. });
  482.  
  483. export default connect(
  484. state => ({
  485. user: state.user,
  486. profile: state.user.profile || {},
  487. }),
  488. dispatch => ({
  489. setProfile: profile => dispatch(actions.setProfile(profile)),
  490. }),
  491. )(Profile);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement