BlueWallet/screen/wallets/hodlHodl.js

1045 lines
85 KiB
JavaScript
Raw Normal View History

/* global alert */
import React, { Component } from 'react';
import {
Linking,
StyleSheet,
View,
Text,
FlatList,
TouchableHighlight,
TouchableOpacity,
Keyboard,
KeyboardAvoidingView,
Platform,
Image,
TextInput,
2020-03-26 00:13:14 +01:00
ScrollView,
} from 'react-native';
2020-03-26 00:13:14 +01:00
import { BlueNavigationStyle, BlueLoading, BlueCard, SafeBlueArea } from '../../BlueComponents';
import PropTypes from 'prop-types';
import { HodlHodlApi } from '../../class/hodl-hodl-api';
import Modal from 'react-native-modal';
import { Icon } from 'react-native-elements';
const A = require('../../analytics');
const CURRENCY_CODE_ANY = '_any';
const METHOD_ANY = '_any';
const styles = StyleSheet.create({
header: {
alignItems: 'center',
flex: 1,
},
headerRow: {
flexDirection: 'row',
},
poweredBy: {
position: 'absolute',
top: -10,
left: 0,
fontSize: 10,
color: '#0c2550',
},
title: {
fontWeight: 'bold',
fontSize: 34,
color: '#0c2550',
},
chooseSide: {
2020-03-26 00:13:14 +01:00
backgroundColor: '#EEF0F4',
borderRadius: 20,
width: 100,
height: 35,
2020-03-26 00:13:14 +01:00
top: 3,
paddingLeft: 2,
paddingBottom: 6,
paddingTop: 6,
paddingRight: 0,
justifyContent: 'center',
alignItems: 'center',
flex: 0.65,
flexDirection: 'row',
},
chooseSideText: {
fontSize: 17,
fontWeight: '600',
color: '#9AA0AA',
},
chooseSideIcon: {
paddingLeft: 0,
paddingRight: 0,
},
filter: {
2020-03-26 00:13:14 +01:00
backgroundColor: '#EEF0F4',
borderRadius: 20,
2020-03-26 00:13:14 +01:00
height: 44,
justifyContent: 'center',
alignItems: 'center',
marginTop: 15,
},
filterRow: {
width: '100%',
alignItems: 'center',
flex: 1,
flexDirection: 'row',
},
filterLocation: {
top: 0,
left: 5,
color: '#0c2550',
fontSize: 20,
2020-03-26 00:13:14 +01:00
fontWeight: '500',
},
filterOpenTouch: {
2020-03-26 00:13:14 +01:00
backgroundColor: '#CCDDF9',
borderRadius: 20,
width: 110,
flex: 1,
flexDirection: 'row',
2020-03-26 00:13:14 +01:00
height: 36,
paddingLeft: 8,
justifyContent: 'center',
alignItems: 'center',
right: 4,
position: 'absolute',
},
filterOpenText: {
color: '#2f5fb3',
fontSize: 18,
fontWeight: '600',
},
modal: {
justifyContent: 'flex-end',
margin: 0,
},
modalContent: {
backgroundColor: '#FFFFFF',
padding: 22,
justifyContent: 'center',
alignItems: 'center',
borderTopLeftRadius: 16,
borderTopRightRadius: 16,
borderColor: 'rgba(0, 0, 0, 0.1)',
minHeight: 400,
height: 400,
},
modalContentShort: {
backgroundColor: '#FFFFFF',
padding: 22,
justifyContent: 'center',
alignItems: 'center',
borderTopLeftRadius: 16,
borderTopRightRadius: 16,
borderColor: 'rgba(0, 0, 0, 0.1)',
minHeight: 200,
height: 200,
},
modalSearch: {
flexDirection: 'row',
2020-03-26 00:13:14 +01:00
borderColor: '#EEF0F4',
borderBottomColor: '#EEF0F4',
borderWidth: 1.0,
borderBottomWidth: 0.5,
2020-03-26 00:13:14 +01:00
backgroundColor: '#EEF0F4',
minHeight: 48,
height: 48,
marginHorizontal: 20,
alignItems: 'center',
marginVertical: 8,
2020-03-26 00:13:14 +01:00
borderRadius: 26,
width: '100%',
},
modalSearchText: {
flex: 1,
marginHorizontal: 8,
minHeight: 33,
paddingLeft: 6,
paddingRight: 6,
},
modalSearchText2: {
flex: 1,
fontSize: 17,
marginHorizontal: 8,
minHeight: 33,
paddingLeft: 6,
paddingRight: 6,
},
modalSearchIcon: {
left: -10,
},
modalList: {
width: '100%',
},
itemRoot: {
backgroundColor: 'white',
},
item: {
backgroundColor: 'white',
flex: 1,
flexDirection: 'row',
paddingTop: 20,
paddingBottom: 20,
},
itemText: {
fontSize: 20,
color: '#0c2550',
},
itemTextBold: {
fontWeight: 'bold',
},
itemTextNormal: {
fontWeight: 'normal',
},
itemRow: {
paddingLeft: 10,
flex: 1,
flexDirection: 'row',
},
itemValue: {
color: '#9AA0AA',
right: 0,
position: 'absolute',
},
itemValueText1: {
fontSize: 18,
color: '#9AA0AA',
},
itemValueText2: {
fontSize: 20,
color: '#9AA0AA',
},
offers: {
paddingHorizontal: 24,
},
offersList: {
marginTop: 24,
flex: 1,
},
offersListContent: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 0,
},
noOffers: {
textAlign: 'center',
color: '#9AA0AA',
paddingHorizontal: 16,
},
offer: {
backgroundColor: 'white',
paddingTop: 16,
paddingBottom: 16,
},
offerRow: {
backgroundColor: 'white',
flex: 1,
flexDirection: 'row',
},
offerAvatar: {
width: 40,
height: 40,
borderRadius: 40,
},
offerNickname: {
color: '#0c2550',
fontSize: 18,
fontWeight: '600',
},
offerRating: {
color: '#9AA0AA',
},
offerText: {
color: '#9AA0AA',
paddingTop: 10,
},
offerFooter: {
flex: 1,
flexDirection: 'row',
paddingTop: 10,
paddingBottom: 10,
alignItems: 'center',
},
offerPrice: {
backgroundColor: '#EEF0F4',
borderRadius: 20,
paddingLeft: 8,
paddingRight: 8,
height: 26,
justifyContent: 'center',
alignItems: 'center',
},
offerPriceText: {
fontWeight: '600',
fontSize: 14,
color: '#9AA0AA',
},
offerAmount: {
color: '#9AA0AA',
fontSize: 12,
paddingLeft: 10,
},
// allOffersText: {
// fontSize: 12,
// color: '#9AA0AA',
// position: 'absolute',
// top: 0,
// left: 15,
// },
paddingLeft: {
paddingLeft: 10,
},
separator: {
height: 0.5,
width: '100%',
backgroundColor: '#C8C8C8',
},
});
const HodlApi = new HodlHodlApi();
export default class HodlHodl extends Component {
static navigationOptions = ({ navigation }) => ({
...BlueNavigationStyle(),
title: '',
});
constructor(props) {
super(props);
/** @type {AbstractWallet} */
2020-05-27 14:12:17 +03:00
let wallet = props.route.params.wallet;
this.state = {
isLoading: true,
isChooseSideModalVisible: false,
isChooseCountryModalVisible: false,
isFiltersModalVisible: false,
isChooseCurrencyVisible: false,
isChooseMethodVisible: false,
currency: false, // means no currency filtering is enabled by default
method: false, // means no payment method filtering is enabled by default
side: HodlHodlApi.FILTERS_SIDE_VALUE_SELL, // means 'show me sell offers as Im buying'
wallet,
offers: [],
countries: [], // list of hodlhodl supported countries. filled later via api
currencies: [], // list of hodlhodl supported currencies. filled later via api
methods: [], // list of hodlhodl payment methods. filled later via api
country: HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL, // country currently selected by user to display orders on screen. this is country code
myCountryCode: HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL, // current user's country. filled later, via geoip api
};
}
/**
* Fetch offers and set those offers into state
*
* @returns {Promise<void>}
*/
async fetchOffers() {
let pagination = {
[HodlHodlApi.PAGINATION_LIMIT]: 200,
};
let filters = {
[HodlHodlApi.FILTERS_COUNTRY]: this.state.country,
[HodlHodlApi.FILTERS_SIDE]: this.state.side,
[HodlHodlApi.FILTERS_ASSET_CODE]: HodlHodlApi.FILTERS_ASSET_CODE_VALUE_BTC,
[HodlHodlApi.FILTERS_INCLUDE_GLOBAL]: this.state.country === HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL,
[HodlHodlApi.FILTERS_ONLY_WORKING_NOW]: true, // so there wont be any offers which user tries to open website says 'offer not found'
};
if (this.state.currency) {
filters[HodlHodlApi.FILTERS_CURRENCY_CODE] = this.state.currency;
}
if (this.state.method) {
filters[HodlHodlApi.FILTERS_PAYMENT_METHOD_ID] = this.state.method;
}
let sort = {
[HodlHodlApi.SORT_BY]: HodlHodlApi.SORT_BY_VALUE_PRICE,
[HodlHodlApi.SORT_DIRECTION]: HodlHodlApi.SORT_DIRECTION_VALUE_ASC,
};
const offers = await HodlApi.getOffers(pagination, filters, sort);
this.setState({
offers,
});
}
async fetchMyCountry() {
let myCountryCode = await HodlApi.getMyCountryCode();
this.setState({
myCountryCode,
country: myCountryCode, // we start with orders from current country
});
}
/**
* fetches all countries from API and sets them to state
*
* @returns {Promise<void>}
**/
async fetchListOfCountries() {
let countries = await HodlApi.getCountries();
this.setState({ countries });
}
/**
* fetches all currencies from API and sets them to state
*
* @returns {Promise<void>}
**/
async fetchListOfCurrencies() {
let currencies = await HodlApi.getCurrencies();
this.setState({ currencies });
}
/**
* fetches all payment methods from API and sets them to state
*
* @returns {Promise<void>}
**/
async fetchListOfMethods() {
let methods = await HodlApi.getPaymentMethods(this.state.country || HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL);
this.setState({ methods });
}
async componentDidMount() {
console.log('wallets/hodlHodl - componentDidMount');
A(A.ENUM.NAVIGATED_TO_WALLETS_HODLHODL);
try {
await this.fetchMyCountry();
await this.fetchOffers();
} catch (Error) {
alert(Error.message);
return;
}
this.setState({
isLoading: false,
});
this.fetchListOfCountries();
this.fetchListOfCurrencies();
this.fetchListOfMethods();
}
async _refresh() {
this.setState(
{
isLoading: true,
},
async () => {
await this.fetchOffers();
this.setState({
isLoading: false,
});
},
);
}
_onPress(item) {
Linking.openURL('https://hodlhodl.com/offers/' + item.id);
}
_onCountryPress(item) {
this.setState(
{
country: item.code,
method: false, // invalidate currently selected payment method, as it is probably not valid for the new country
currency: false, // invalidate currently selected currency, as it is probably not valid for the new country
isChooseCountryModalVisible: false,
isLoading: true,
},
async () => {
await this.fetchOffers();
this.setState({
isLoading: false,
});
this.fetchListOfMethods(); // once selected country changed we fetch payment methods for this country
},
);
}
_onCurrencyPress(item) {
this.setState(
{
currency: item.code === CURRENCY_CODE_ANY ? false : item.code,
isLoading: true,
isChooseCurrencyVisible: false,
},
async () => {
await this.fetchOffers();
this.setState({
isLoading: false,
});
},
);
}
_onMethodPress(item) {
this.setState(
{
method: item.id === METHOD_ANY ? false : item.id,
isLoading: true,
isChooseMethodVisible: false,
},
async () => {
await this.fetchOffers();
this.setState({
isLoading: false,
});
},
);
}
_onSidePress(item) {
this.setState(
{
isChooseSideModalVisible: false,
isLoading: true,
side: item.code,
},
async () => {
await this.fetchOffers();
this.setState({
isLoading: false,
});
},
);
}
getItemText(item) {
let { title, description } = item;
title = title || '';
let ret = title;
if (description) {
if (description.startsWith(title)) title = '';
ret =
title +
'\n' +
description
.split('\n')
.slice(0, 2)
.join('\n');
}
if (ret.length >= 200) ret = ret.substr(0, 200) + '...';
return ret;
}
getMethodName(id) {
for (let m of this.state.methods) {
if (m.id === id) return m.name;
}
return '';
}
getItemPrice(item) {
let price = item.price.toString();
if (price.length > 8) price = Math.round(item.price).toString();
switch (item.currency_code) {
case 'USD':
return '$ ' + price;
case 'GBP':
return '£ ' + price;
case 'RUB':
return '₽ ' + price;
case 'EUR':
return '€ ' + price;
case 'UAH':
return '₴ ' + price;
default:
return price + (price.length >= 9 ? '' : ' ' + item.currency_code); // too lengthy prices dont render currency code
}
}
getNativeCountryName() {
if (this.state.country === this.state.myCountryCode) return 'Near me';
for (let c of this.state.countries) {
if (c.code === this.state.country) return c.native_name;
}
return 'Global offers';
}
renderChooseSideModal = () => {
return (
<Modal
isVisible={this.state.isChooseSideModalVisible}
style={styles.modal}
onBackdropPress={() => {
Keyboard.dismiss();
this.setState({ isChooseSideModalVisible: false });
}}
>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
<View style={styles.modalContentShort}>
<FlatList
2020-03-26 00:13:14 +01:00
scrollEnabled={false}
style={styles.modalList}
ItemSeparatorComponent={() => <View style={styles.separator} />}
data={[
{ code: HodlHodlApi.FILTERS_SIDE_VALUE_SELL, name: "I'm buying bitcoin" },
{ code: HodlHodlApi.FILTERS_SIDE_VALUE_BUY, name: "I'm selling bitcoin" },
]}
keyExtractor={(item, index) => item.code}
renderItem={({ item, index, separators }) => (
<TouchableHighlight
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}
onPress={() => this._onSidePress(item)}
>
<View style={styles.item}>
<Text style={[styles.itemText, this.state.side === item.code ? styles.itemTextBold : styles.itemTextNormal]}>
2020-03-26 20:03:27 +00:00
{item.name}
</Text>
</View>
</TouchableHighlight>
)}
/>
</View>
</KeyboardAvoidingView>
</Modal>
);
};
renderFiltersModal = () => {
return (
<Modal
isVisible={this.state.isFiltersModalVisible}
style={styles.modal}
onModalHide={() => {
if (this.state.openNextModal) {
const openNextModal = this.state.openNextModal;
this.setState({
openNextModal: false,
[openNextModal]: true,
});
}
}}
onBackdropPress={() => {
Keyboard.dismiss();
this.setState({ isFiltersModalVisible: false });
}}
>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
<View style={styles.modalContentShort}>
<FlatList
2020-03-26 00:13:14 +01:00
scrollEnabled={false}
style={styles.modalList}
ItemSeparatorComponent={() => <View style={styles.separator} />}
data={[
{ code: 'currency', native_name: 'Currency' },
{ code: 'method', native_name: 'Payment method' },
]}
keyExtractor={(item, index) => item.code}
renderItem={({ item, index, separators }) => (
<TouchableHighlight
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}
onPress={() => {
if (item.code === 'currency') this.setState({ isFiltersModalVisible: false, openNextModal: 'isChooseCurrencyVisible' });
if (item.code === 'method') this.setState({ isFiltersModalVisible: false, openNextModal: 'isChooseMethodVisible' });
}}
>
<View style={styles.itemRoot}>
<View style={styles.item}>
<View style={styles.itemRow}>
<Text style={styles.itemText}>{item.native_name}</Text>
<View style={styles.itemValue}>
{item.code === 'currency' && (
<Text style={styles.itemValueText1}> {this.state.currency ? this.state.currency + ' ' : 'Detail '} </Text>
)}
{item.code === 'method' && (
<Text style={styles.itemValueText2}>
{' '}
2020-03-26 00:13:14 +01:00
{this.state.method ? this.getMethodName(this.state.method) + ' ' : 'Detail '}
</Text>
)}
</View>
</View>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</KeyboardAvoidingView>
</Modal>
);
};
renderChooseContryModal = () => {
let countries2render = [];
// first, we include in the list current country
for (let country of this.state.countries) {
if (country.code === this.state.country) {
countries2render.push(country);
}
}
// next, we include option for user to set GLOBAL for offers
countries2render.push({
code: HodlHodlApi.FILTERS_COUNTRY_VALUE_GLOBAL,
name: 'Global offers',
native_name: 'Global offers',
});
// lastly, we include other countries
for (let country of this.state.countries) {
if (country.code !== this.state.country) {
// except currently selected one
if (this.state.countrySearchInput) {
// if user typed something in search box we apply that filter
if (
country.name.toLocaleLowerCase().includes(this.state.countrySearchInput.toLocaleLowerCase()) ||
country.native_name.toLocaleLowerCase().includes(this.state.countrySearchInput.toLocaleLowerCase())
) {
countries2render.push(country);
}
} else {
// otherwise just put the country in the list
countries2render.push(country);
}
}
}
return (
<Modal
isVisible={this.state.isChooseCountryModalVisible}
style={styles.modal}
onBackdropPress={() => {
Keyboard.dismiss();
this.setState({ isChooseCountryModalVisible: false });
}}
>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
<View style={styles.modalContent}>
<View style={styles.modalSearch}>
<TextInput
onChangeText={text => this.setState({ countrySearchInput: text })}
placeholder={'Search..'}
2020-03-26 20:03:27 +00:00
placeholderTextColor="#9AA0AA"
value={this.state.countrySearchInput || ''}
numberOfLines={1}
style={styles.modalSearchText2}
/>
<Icon name="search" type="material" size={20} color="gray" containerStyle={styles.modalSearchIcon} />
</View>
<FlatList
style={styles.modalList}
ItemSeparatorComponent={() => <View style={styles.separator} />}
data={countries2render}
keyExtractor={(item, index) => item.code}
renderItem={({ item, index, separators }) => (
<TouchableHighlight
onPress={() => this._onCountryPress(item)}
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}
>
<View style={styles.itemRoot}>
<View style={styles.item}>
<View style={styles.paddingLeft}>
<Text style={[styles.itemText, item.code === this.state.country ? styles.itemTextBold : styles.itemTextNormal]}>
{item.native_name}
</Text>
</View>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</KeyboardAvoidingView>
</Modal>
);
};
renderChooseCurrencyModal = () => {
let currencies2render = [];
// first, option to choose any currency
currencies2render.push({
code: CURRENCY_CODE_ANY,
name: 'Any',
});
// lastly, we include other countries
for (let curr of this.state.currencies) {
if (this.state.currencySearchInput) {
// if user typed something in search box we apply that filter
if (
curr.name.toLocaleLowerCase().includes(this.state.currencySearchInput.toLocaleLowerCase()) ||
curr.code.toLocaleLowerCase().includes(this.state.currencySearchInput.toLocaleLowerCase())
) {
currencies2render.push(curr);
}
} else {
// otherwise just put the country in the list
currencies2render.push(curr);
}
}
return (
<Modal
isVisible={this.state.isChooseCurrencyVisible}
style={styles.modal}
onBackdropPress={() => {
Keyboard.dismiss();
this.setState({ isChooseCurrencyVisible: false });
}}
>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
<View style={styles.modalContent}>
<View style={styles.modalSearch}>
<TextInput
onChangeText={text => this.setState({ currencySearchInput: text })}
placeholder={'Search..'}
2020-03-26 00:13:14 +01:00
placeholderTextColor="#9AA0AA"
value={this.state.currencySearchInput || ''}
numberOfLines={1}
style={styles.modalSearchText}
/>
<Icon name="search" type="material" size={20} color="gray" containerStyle={styles.modalSearchIcon} />
</View>
<FlatList
style={styles.modalList}
ItemSeparatorComponent={() => <View style={styles.separator} />}
data={currencies2render}
keyExtractor={(item, index) => item.code}
renderItem={({ item, index, separators }) => (
<TouchableHighlight
onPress={() => this._onCurrencyPress(item)}
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}
>
<View style={styles.itemRoot}>
<View style={styles.item}>
<View style={styles.paddingLeft}>
<Text
style={[
styles.itemText,
item.code === this.state.currency || (item.code === CURRENCY_CODE_ANY && this.state.currency === false)
? styles.itemTextBold
: styles.itemTextNormal,
]}
>
{item.name} {item.code !== CURRENCY_CODE_ANY && '[' + item.code + ']'}
</Text>
</View>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</KeyboardAvoidingView>
</Modal>
);
};
renderChooseMethodModal = () => {
let methods2render = [];
// first, option to choose any currency
methods2render.push({
id: METHOD_ANY,
name: 'Any',
});
// lastly, we include other countries
for (let curr of this.state.methods) {
if (this.state.methodSearchInput) {
// if user typed something in search box we apply that filter
if (
curr.name.toLocaleLowerCase().includes(this.state.methodSearchInput.toLocaleLowerCase()) ||
curr.type.toLocaleLowerCase().includes(this.state.methodSearchInput.toLocaleLowerCase())
) {
methods2render.push(curr);
}
} else {
// otherwise just put the country in the list
methods2render.push(curr);
}
}
return (
<Modal
isVisible={this.state.isChooseMethodVisible}
style={styles.modal}
onBackdropPress={() => {
Keyboard.dismiss();
this.setState({ isChooseMethodVisible: false });
}}
>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'position' : null}>
<View style={styles.modalContent}>
<View style={styles.modalSearch}>
<TextInput
onChangeText={text => this.setState({ methodSearchInput: text })}
placeholder={'Search..'}
2020-03-26 00:13:14 +01:00
placeholderTextColor="#9AA0AA"
value={this.state.methodSearchInput || ''}
numberOfLines={1}
style={styles.modalSearchText}
/>
<Icon name="search" type="material" size={20} color="gray" containerStyle={styles.modalSearchIcon} />
</View>
<FlatList
style={styles.modalList}
ItemSeparatorComponent={() => <View style={styles.separator} />}
data={methods2render}
keyExtractor={(item, index) => item.id}
renderItem={({ item, index, separators }) => (
<TouchableHighlight
onPress={() => this._onMethodPress(item)}
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}
>
<View style={styles.itemRoot}>
<View style={styles.item}>
<View style={styles.paddingLeft}>
<Text
style={[
styles.itemText,
item.id === this.state.method || (item.id === METHOD_ANY && this.state.method === false)
? styles.itemTextBold
: styles.itemTextNormal,
]}
>
{item.name} {item.id !== METHOD_ANY && '[' + item.type + ']'}
</Text>
</View>
</View>
</View>
</TouchableHighlight>
)}
/>
</View>
</KeyboardAvoidingView>
</Modal>
);
};
render() {
return (
2020-03-26 00:13:14 +01:00
<SafeBlueArea>
<BlueCard style={styles.header}>
<View style={styles.headerRow}>
<Text style={styles.poweredBy}>Powered by HodlHodl®</Text>
<Text style={styles.title}>Local Trader </Text>
<TouchableOpacity
style={styles.chooseSide}
onPress={() => {
this.setState({ isChooseSideModalVisible: true });
}}
>
<Text style={styles.chooseSideText}>{this.state.side === HodlHodlApi.FILTERS_SIDE_VALUE_SELL ? 'Buying' : 'Selling'}</Text>
<Icon name="expand-more" type="material" size={22} color="#9AA0AA" containerStyle={styles.chooseSideIcon} />
</TouchableOpacity>
</View>
<View style={styles.filter}>
<View style={styles.filterRow}>
{/* <Text style={styles.allOffersText}>All offers</Text> */}
<Icon name="place" type="material" size={20} color="#0c2550" containerStyle={styles.paddingLeft} />
<TouchableOpacity onPress={() => this.setState({ isChooseCountryModalVisible: true }) /* this.changeCountry() */}>
<Text style={styles.filterLocation}>{this.getNativeCountryName()}</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.filterOpenTouch}
onPress={() => {
this.setState({ isFiltersModalVisible: true });
}}
>
<Text style={styles.filterOpenText}>Filters</Text>
<Icon name="filter-list" type="material" size={24} color="#2f5fb3" containerStyle={styles.paddingLeft} />
</TouchableOpacity>
</View>
</View>
2020-03-26 20:03:27 +00:00
</BlueCard>
{(this.state.isLoading && <BlueLoading />) || (
<ScrollView style={styles.offers}>
<FlatList
onRefresh={() => this._refresh()}
refreshing={this.state.isLoading}
style={styles.offersList}
contentContainerStyle={styles.offersListContent}
ItemSeparatorComponent={() => <View style={styles.separator} />}
data={this.state.offers}
ListEmptyComponent={() => <Text style={styles.noOffers}>No offers. Try to change "Near me" to Global offers!</Text>}
renderItem={({ item, index, separators }) => (
<TouchableHighlight
onPress={() => this._onPress(item)}
onShowUnderlay={separators.highlight}
onHideUnderlay={separators.unhighlight}
>
<View style={styles.offer}>
<View style={styles.offerRow}>
<View>
<Image
style={styles.offerAvatar}
source={{
2020-04-03 18:17:13 +01:00
uri: item.trader.avatar_url.endsWith('.svg')
? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA/oAAAQCCAYAAAAcgINbAAAgAElEQVR4Xuzdi3dcZbk/8GfvSdKmbdr0fqdFURFUUPDyw9v501UuRxAQQQQBtfd703vTJpm9f2ta9IgCbZpMZu/3+cw6rFad2fv5fp53nbW+ZGZSvfPOO214ECBAgAABAgQIECBAgAABAkUIVHcWzir6RaxSCAIECBAgQIAAAQIECBAgEKHoOwUECBAgQIAAAQIECBAgQKAgAUW/oGWKQoAAAQIECBAgQIAAAQIEFH1ngAABAgQIECBAgAABAgQIFCSg6Be0TFEIECBAgAABAgQIECBAgICi7wwQIECAAAECBAgQIECAAIGCBBT9gpYpCgECBAgQIECAAAECBAgQUPSdAQIECBAgQIAAAQIECBAgUJCAol/QMkUhQIAAAQIECBAgQIAAAQKKvjNAgAABAgQIECBAgAABAgQKElD0C1qmKAQIECBAgAABAgQIECBAQNF3BggQIECAAAECBAgQIECAQEECin5ByxSFAAECBAgQIECAAAECBAgo+s4AAQIECBAgQIAAAQIECBAoSEDRL2iZohAgQIAAAQIECBAgQIAAAUXfGSBAgAABAgQIECBAgAABAgUJKPoFLVMUAgQIECBAgAABAgQIECCg6DsDBAgQIECAAAECBAgQIECgIAFFv6BlikKAAAECBAgQIECAAAECBBR9Z4AAAQIECBAgQIAAAQIECBQkoOgXtExRCBAgQIAAAQIECBAgQICAou8MECBAgAABAgQIECBAgACBggQU/YKWKQoBAgQIECBAgAABAgQIEFD0nQECBAgQIECAAAECBAgQIFCQgKJf0DJFIUCAAAECBAgQIECAAAECir4zQIAAAQIECBAgQIAAAQIEChJQ9AtapigECBAgQIAAAQIECBAgQEDRdwYIECBAgAABAgQIECBAgEBBAop+QcsUhQABAgQIECBAgAABAgQIKPrOAAECBAgQIECAAAECBAgQKEhA0S9omaIQIECAAAECBAgQIECAAAFF3xkgQIAAAQIECBAgQIAAAQIFCSj6BS1TFAIECBAgQIAAAQIECBAgoOg7AwQIECBAgAABAgQIECBAoCABRb+gZYpCgAABAgQIECBAgAABAgQUfWeAAAECBAgQIECAAAECBAgUJKDoF7RMUQgQIECAAAECBAgQIECAgKLvDBAgQIAAAQIECBAgQIAAgYIEFP2ClikKAQIECBAgQIAAAQIECBBQ9J0BAgQIECBAgAABAgQIECBQkICiX9AyRSFAgAABAgQIECBAgAABAoq+M0CAAAECBAgQIECAAAECBAoSUPQLWqYoBAgQIECAAAECBAgQIEBA0XcGCBAgQIAAAQIECBAgQIBAQQKKfkHLFIUAAQIECBAgQIAAAQIECCj6zgABAgQIECBAgAABAgQIEChIQNEvaJmiECBAgAABAgQIECBAgAABRd8ZIECAAAECBAgQIECAAAECBQko+gUtUxQCBAgQIECAAAECBAgQIKDoOwMECBAgQIAAAQIECBAgQKAgAUW/oGWKQoAAAQIECBAgQIAAAQIEFH1ngAABAgQIECBAgAABAgQIFCSg6Be0TFEIECBAgAABAgQIECBAgICi7wwQIECAAAECBAgQIECAAIGCBBT9gpYpCgECBAgQIECAAAECBAgQUPSdAQIECBAgQIAAAQIECBAgUJCAol/QMkUhQIAAAQIECBAgQIAAAQKKvjNAgAABAgQIECBAgAABAgQKElD0C1qmKAQIECBAgAABAgQIECBAQNF3BggQIECAAAECBAgQIECAQEECin5ByxSFAAECBAgQIECAAAECBAgo+s4AAQIECBAgQIAAAQIECBAoSEDRL2iZohAgQIAAAQIECBAgQIAAAUXfGSBAgAABAgQIECBAgAABAgUJKPoFLVMUAgQIECBAgAABAgQIECCg6DsDBAgQIECAAAECBAgQIECgIAFFv6BlikKAAAECBAgQIECAAAECBBR9Z4AAAQIECBAgQIAAAQIECBQkoOgXtExRCBAgQIAAAQIECBAgQICAou8MECBAgAABAgQIECBAgACBggQU/YKWKQoBAgQIECBAgAABAgQIEFD0nQECBAgQIECAAAECBAgQIFCQgKJf0DJFIUCAAAECBAgQIECAAAECir4zQIAAAQIECBAgQIAAAQIEChJQ9AtapigECBAgQIAAAQIECBAgQEDRdwYIECBAgAABAgQIECBAgEBBAop+QcsUhQABAgQIECBAgAABAgQIKPrOAAECBAgQIECAAAECBAgQKEhA0S9omaIQIECAAAECBAgQIECAAAFF3xkgQIAAAQIECBAgQIAAAQIFCSj6BS1TFAIECBAgQIAAAQIECBAgoOg7AwQIECBAgAABAgQIECBAoCABRb+gZYpCgAABAgQIECBAgAABAgQUfWeAAAECBAgQIECAAAECBAgUJKDoF7RMUQgQIECAAAECBAgQIECAgKLvDBAgQIAAAQIECBAgQIAAgYIEFP2ClikKAQIECBAgQIAAAQIECBBQ9J0BAgQIECBAgAABAgQIECBQkICiX9AyRSFAgAABAgQIECBAgAABAoq+M0CAAAECBAgQIECAAAECBAoSUPQLWqYoBAgQIECAAAECBAgQIEBA0XcGCBAgQIAAAQIECBAgQIBAQQKKfkHLFIUAAQIECBAgQIAAAQIECCj6zgABAgQIECBAgAABAgQIEChIQNEvaJmiECBAgAABAgQIECBAgAABRd8ZIECAAAECBAgQIECAAAECBQko+gUtUxQCBAgQIECAAAECBAgQIKDoOwMECBAgQIAAAQIECBAgQKAgAUW/oGWKQoAAAQIECBAgQIAAAQIEFH1ngAABAgQIECBAgAABAgQIFCSg6Be0TFEIECBAgAABAgQIECBAgICi7wwQIECAAAECBAgQIECAAIGCBBT9gpYpCgECBAgQIECAAAECBAgQUPSdAQIECBAgQIAAAQIECBAgUJCAol/QMkUhQIAAAQIECBAgQIAAAQKKvjNAgAABAgQIECBAgAABAgQKElD0C1qmKAQIECBAgAABAgQIECBAQNF3BggQIECAAAECBAgQIECAQEECin5ByxSFAAECBAgQIECAAAECBAgo+s4AAQIECBAgQIAAAQIECBAoSEDRL2iZohAgQIAAAQIECBAgQIAAAUXfGSBAgAABAgQIECBAgAABAgUJKPoFLVMUAgQIECBAgAABAgQIECCg6DsDBAgQIECAAAECBAgQIECgIAFFv6BlikKAAAECBAgQIECAAAECBBR9Z4AAAQIECBAgQIAAAQIECBQkoOgXtExRCBAgQIAAAQIECBAgQICAou8MECBAgAABAgQIECBAgACBggQU/YKWKQoBAgQIECBAgAABAgQIEFD0nQECBAgQIECAAAECBAgQIFCQgKJf0DJFIUCAAAECBAgQIECAAAECir4zQIAAAQIECBAgQIAAAQIEChJQ9AtapigECBAgQIAAAQIECBAgQEDRdwYIECBAgAABAgQIECBAgEBBAop+QcsUhQABAgQIECBAgAABAgQIKPrOAAECBAgQIECAAAECBAgQKEhA0S9omaIQIECAAAECBAgQIECAAAFF3xkgQIAAAQIECBAgQIAAAQIFCSj6BS1TFAIECBAgQIAAAQIECBAgoOg7AwQIECBAgAABAgQIECBAoCABRb+gZYpCgAABAgQIECBAgAABAgQUfWeAAAECBAgQIECAAAECBAgUJKDoF7RMUQgQIECAAAECBAgQIECAgKLvDBAgQIAAAQIECBAgQIAAgYIEFP2ClikKAQIECBAgQIAAAQIECBBQ9J0BAgQIECBAgAABAgQIECBQkICiX9AyRSFAgAABAgQIECBAgAABAoq+M0CAAAECBAgQIECAAAECBAoSUPQLWqYoBAgQIECAAAECBAgQIEBA0XcGCBAgQIAAAQIECBAgQIBAQQKKfkHLFIUAAQIECBAgQIAAAQIECCj6zgABAgQIECBAgAABAgQI
: item.trader.avatar_url,
}}
/>
</View>
<View style={styles.paddingLeft}>
<Text style={styles.offerNickname}>{item.trader.login}</Text>
<Text style={styles.offerRating}>
{item.trader.trades_count > 0 ? Math.round(item.trader.rating * 100) + '%' : 'No rating'}
</Text>
</View>
</View>
<Text style={styles.offerText}>{this.getItemText(item)}</Text>
<View style={styles.offerFooter}>
<View style={styles.offerPrice}>
<Text style={styles.offerPriceText}>{this.getItemPrice(item)}</Text>
</View>
<Text style={styles.offerAmount}>
Min/Max: {item.min_amount.replace('.00', '')} - {item.max_amount.replace('.00', '')} {item.currency_code}
</Text>
</View>
</View>
</TouchableHighlight>
)}
/>
2020-03-26 00:13:14 +01:00
</ScrollView>
2020-03-26 20:03:27 +00:00
)}
{this.renderChooseSideModal()}
{this.renderChooseContryModal()}
{this.renderFiltersModal()}
{this.renderChooseCurrencyModal()}
{this.renderChooseMethodModal()}
2020-03-26 20:03:27 +00:00
</SafeBlueArea>
);
}
}
HodlHodl.propTypes = {
2020-05-27 14:12:17 +03:00
route: PropTypes.shape({
params: PropTypes.shape({
wallet: PropTypes.object,
}),
}),
};