-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Browser Dapp Showcase #423
Changes from 17 commits
d29a2d9
683579a
58a607c
9444de0
3f79063
5c3cb85
1b9a2bc
0a2f6e0
206078b
67c5f11
1c51cab
3bd58c3
dd05c1b
0e5f12c
df03f8a
3cbad79
49d5f01
cdeed88
f6550e5
b68432a
989ba7f
3f08f36
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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> | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
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: { | ||
color: colors.fontSecondary, | ||
...fontStyles.normal | ||
}, | ||
fallbackTextStyle: { | ||
fontSize: 12 | ||
}, | ||
wrapper: { | ||
flex: 1 | ||
} | ||
}); | ||
|
||
/** | ||
* 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 = <Text style={styles.noBookmarks}>{strings('home_page.no_bookmarks')}</Text>; | ||
} | ||
return ( | ||
<View style={styles.bookmarksWrapper}> | ||
<View style={styles.bookmarksItemsWrapper}>{content}</View> | ||
<ActionSheet | ||
ref={this.createActionSheetRef} | ||
title={strings('home_page.remove_bookmark_title')} | ||
options={['Remove', '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)); |
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> | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import React, { Component } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { Text, StyleSheet, View } 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: 35, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this icons are bigger, I'd refactor the websiteIcon component to receive a prop Should look something like this: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice! didn't know this |
||
width: 35 | ||
}, | ||
iconWrapper: { | ||
borderRadius: 8, | ||
height: 88, | ||
width: 88, | ||
backgroundColor: colors.white, | ||
alignItems: 'center', | ||
justifyContent: 'center', | ||
shadowOpacity: 0.25, | ||
shadowOffset: { | ||
width: 0, | ||
height: 0 | ||
} | ||
}, | ||
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 | ||
}; | ||
|
||
render() { | ||
const { name, url, description } = this.props; | ||
return ( | ||
<View style={styles.wrapper}> | ||
<View style={styles.iconWrapper}> | ||
<WebsiteIcon style={styles.icon} title={name} url={url} /> | ||
</View> | ||
<View style={styles.contentWrapper}> | ||
<Text style={styles.name}>{name}</Text> | ||
<Text style={styles.description} numberOfLines={3}> | ||
{description} | ||
</Text> | ||
</View> | ||
</View> | ||
); | ||
} | ||
} |
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> | ||
`; |
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 } = item; | ||
return ( | ||
<TouchableOpacity | ||
key={url} | ||
onPress={() => this.props.goTo(url)} // eslint-disable-line react/jsx-no-bind | ||
> | ||
<FeaturedItem name={name} url={url} description={description} /> | ||
</TouchableOpacity> | ||
); | ||
}; | ||
render() { | ||
return ( | ||
<View style={styles.wrapper}> | ||
<FlatList data={dappList} keyExtractor={this.keyExtractor} renderItem={this.renderItem} /> | ||
</View> | ||
); | ||
} | ||
} |
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(); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move to locales