Skip to content

Commit

Permalink
Browser Dapp Showcase (#423)
Browse files Browse the repository at this point in the history
* browser top done

* tab bar and favorites working

* remove bookmarks

* featured dapps with basic styles

* go to featured

* favorites working fine

* favorite item style

* final styles

* url autocomplete

* locales

* move components to UI

* snapshots

* rename compoennt

* missin locale

* clean after search

* small comments

* pixel ratio

* fix android and empty favorites

* more android fixes
  • Loading branch information
estebanmino authored Feb 21, 2019
1 parent da97c33 commit 401c12e
Show file tree
Hide file tree
Showing 16 changed files with 568 additions and 186 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`BrowserFavorites should render correctly 1`] = `
<ContextConsumer>
<Component />
</ContextConsumer>
`;
163 changes: 163 additions & 0 deletions app/components/UI/BrowserFavorites/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { withNavigation } from 'react-navigation';
import PropTypes from 'prop-types';
import { strings } from '../../../../locales/i18n';
import { TouchableOpacity, Text, StyleSheet, View, FlatList } from 'react-native';
import WebsiteIcon from '../WebsiteIcon';
import { colors, fontStyles } from '../../../styles/common';
import ActionSheet from 'react-native-actionsheet';
import { removeBookmark } from '../../../actions/bookmarks';

const styles = StyleSheet.create({
bookmarksWrapper: {
flex: 1
},
bookmarkItem: {
paddingTop: 20,
paddingHorizontal: 18
},
bookmarksItemsWrapper: {
flex: 1
},

bookmarkTouchable: {
flexDirection: 'row',
alignItems: 'center'
},
bookmarkUrl: {
flex: 1,
...fontStyles.normal
},
bookmarkIco: {
width: 26,
height: 26,
marginRight: 7,
borderRadius: 13
},
noBookmarks: {
fontSize: 16,
color: colors.fontSecondary,
textAlign: 'center',
...fontStyles.bold
},
fallbackTextStyle: {
fontSize: 12
},
wrapper: {
flex: 1
},
noBookmarksWrapper: {
marginTop: 120,
paddingHorizontal: 20
}
});

/**
* Browser favorite sites
*/
class BrowserFavorites extends Component {
static propTypes = {
/**
* Array containing all the bookmark items
*/
bookmarks: PropTypes.array,
/**
* Function to be called when tapping on a bookmark item
*/
goTo: PropTypes.any,
/**
* function that removes a bookmark
*/
removeBookmark: PropTypes.func
};

actionSheet = null;

keyExtractor = item => item.url;

bookmarkUrlToRemove = null;

showRemoveMenu = url => {
this.bookmarkUrlToRemove = url;
this.actionSheet.show();
};

removeBookmark = () => {
const bookmark = this.props.bookmarks.find(bookmark => bookmark.url === this.bookmarkUrlToRemove);
this.props.removeBookmark(bookmark);
};

createActionSheetRef = ref => {
this.actionSheet = ref;
};

renderItem = ({ item }) => {
const { url, name } = item;
return (
<View key={item.url} style={styles.bookmarkItem}>
<TouchableOpacity
style={styles.bookmarkTouchable}
onPress={() => this.props.goTo(url)} // eslint-disable-line react/jsx-no-bind
// eslint-disable-next-line react/jsx-no-bind
onLongPress={() => this.showRemoveMenu(url)}
>
<WebsiteIcon
style={styles.bookmarkIco}
url={url}
title={name}
textStyle={styles.fallbackTextStyle}
/>
<Text numberOfLines={1} style={styles.bookmarkUrl}>
{name}
</Text>
</TouchableOpacity>
</View>
);
};

renderBookmarks() {
const { bookmarks } = this.props;
let content = null;
if (bookmarks.length) {
content = <FlatList data={bookmarks} keyExtractor={this.keyExtractor} renderItem={this.renderItem} />;
} else {
content = (
<View style={styles.noBookmarksWrapper}>
<Text style={styles.noBookmarks}>{strings('home_page.no_bookmarks')}</Text>
</View>
);
}
return (
<View style={styles.bookmarksWrapper}>
<View style={styles.bookmarksItemsWrapper}>{content}</View>
<ActionSheet
ref={this.createActionSheetRef}
title={strings('home_page.remove_bookmark_title')}
options={[strings('browser.remove'), strings('browser.cancel')]}
cancelButtonIndex={1}
destructiveButtonIndex={0}
// eslint-disable-next-line react/jsx-no-bind
onPress={index => (index === 0 ? this.removeBookmark() : null)}
/>
</View>
);
}

render() {
return <View style={styles.wrapper}>{this.renderBookmarks()}</View>;
}
}

const mapStateToProps = state => ({
bookmarks: state.bookmarks
});

const mapDispatchToProps = dispatch => ({
removeBookmark: bookmark => dispatch(removeBookmark(bookmark))
});

export default connect(
mapStateToProps,
mapDispatchToProps
)(withNavigation(BrowserFavorites));
19 changes: 19 additions & 0 deletions app/components/UI/BrowserFavorites/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';
import { shallow } from 'enzyme';
import BrowserFavorites from './';
import configureMockStore from 'redux-mock-store';

const mockStore = configureMockStore();

describe('BrowserFavorites', () => {
it('should render correctly', () => {
const initialState = {
bookmarks: [{ url: 'url', name: 'name' }]
};

const wrapper = shallow(<BrowserFavorites />, {
context: { store: mockStore(initialState) }
});
expect(wrapper.dive()).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`FeaturedItem should render correctly 1`] = `
<ContextConsumer>
<Component />
</ContextConsumer>
`;
85 changes: 85 additions & 0 deletions app/components/UI/BrowserFeatured/FeaturedItem/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Text, StyleSheet, View, PixelRatio } from 'react-native';
import WebsiteIcon from '../../WebsiteIcon';
import { colors, fontStyles } from '../../../../styles/common';

const styles = StyleSheet.create({
wrapper: {
padding: 15,
flex: 1,
flexDirection: 'row'
},
icon: {
height: PixelRatio.getPixelSizeForLayoutSize(15),
width: PixelRatio.getPixelSizeForLayoutSize(15)
},
iconWrapper: {
borderRadius: 8,
height: 88,
width: 88,
backgroundColor: colors.white,
alignItems: 'center',
justifyContent: 'center',
shadowOpacity: 0.25,
shadowOffset: {
width: 0,
height: 0
},
elevation: 5
},
contentWrapper: {
flex: 1,
paddingHorizontal: 18
},
name: {
fontSize: 16,
marginBottom: 7,
...fontStyles.bold
},
description: {
fontSize: 14,
...fontStyles.normal
}
});

/**
* Featured item to be rendered
*/
export default class FeaturedItem extends Component {
static propTypes = {
/**
* Dapp description
*/
description: PropTypes.string,
/**
* Dapp name
*/
name: PropTypes.string,
/**
* Dapp url
*/
url: PropTypes.string,
/**
* Dapp image url, could be undefined
*/
imageUrl: PropTypes.string
};

render() {
const { name, url, description, imageUrl } = this.props;
return (
<View style={styles.wrapper}>
<View style={styles.iconWrapper}>
<WebsiteIcon style={styles.icon} title={name} url={imageUrl || url} />
</View>
<View style={styles.contentWrapper}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.description} numberOfLines={3}>
{description}
</Text>
</View>
</View>
);
}
}
16 changes: 16 additions & 0 deletions app/components/UI/BrowserFeatured/FeaturedItem/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { shallow } from 'enzyme';
import FeaturedItem from './';
import configureMockStore from 'redux-mock-store';

const mockStore = configureMockStore();

describe('FeaturedItem', () => {
it('should render correctly', () => {
const initialState = {};
const wrapper = shallow(<FeaturedItem name={'name'} url={'url'} description={'description'} />, {
context: { store: mockStore(initialState) }
});
expect(wrapper.dive()).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`BrowserFeatured should render correctly 1`] = `
<ContextConsumer>
<Component />
</ContextConsumer>
`;
44 changes: 44 additions & 0 deletions app/components/UI/BrowserFeatured/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React, { Component } from 'react';
import dappList from '../../../util/featured-dapp-list';
import FeaturedItem from './FeaturedItem';
import PropTypes from 'prop-types';
import { TouchableOpacity, FlatList, StyleSheet, View } from 'react-native';

const styles = StyleSheet.create({
wrapper: {
flex: 1
}
});

/**
* Browser features dapps
*/
export default class BrowserFeatured extends Component {
static propTypes = {
/*
* Function to be called when tapping on a favorite item
*/
goTo: PropTypes.any
};

keyExtractor = item => item.name;

renderItem = ({ item }) => {
const { name, description, url, imageUrl } = item;
return (
<TouchableOpacity
key={url}
onPress={() => this.props.goTo(url)} // eslint-disable-line react/jsx-no-bind
>
<FeaturedItem name={name} url={url} description={description} imageUrl={imageUrl} />
</TouchableOpacity>
);
};
render() {
return (
<View style={styles.wrapper}>
<FlatList data={dappList} keyExtractor={this.keyExtractor} renderItem={this.renderItem} />
</View>
);
}
}
16 changes: 16 additions & 0 deletions app/components/UI/BrowserFeatured/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { shallow } from 'enzyme';
import BrowserFeatured from './';
import configureMockStore from 'redux-mock-store';

const mockStore = configureMockStore();

describe('BrowserFeatured', () => {
it('should render correctly', () => {
const initialState = {};
const wrapper = shallow(<BrowserFeatured />, {
context: { store: mockStore(initialState) }
});
expect(wrapper.dive()).toMatchSnapshot();
});
});
Loading

0 comments on commit 401c12e

Please sign in to comment.