diff options
| author | Andrew <saintruler@gmail.com> | 2019-03-11 21:00:02 +0400 |
|---|---|---|
| committer | Andrew <saintruler@gmail.com> | 2019-03-11 21:00:02 +0400 |
| commit | 7e7dd5244e8d26485ad7950a89c04c98c4fef83f (patch) | |
| tree | 810730c4650392080fb87a78d3b527201e89fe4b /frontend/app/screens | |
Initial commit/
Diffstat (limited to 'frontend/app/screens')
47 files changed, 3788 insertions, 0 deletions
diff --git a/frontend/app/screens/articles/article.js b/frontend/app/screens/articles/article.js new file mode 100644 index 0000000..059ab44 --- /dev/null +++ b/frontend/app/screens/articles/article.js @@ -0,0 +1,94 @@ +import React from 'react'; +import axios from 'axios'; + + +import { + ScrollView, + Image, + View, + TouchableOpacity, +} from 'react-native'; +import { + RkCard, + RkText, + RkStyleSheet, +} from 'react-native-ui-kitten'; +import { + Avatar, + SocialBar, +} from '../../components'; +import NavigationType from '../../config/navigation/propTypes'; + + +export class Article extends React.Component { + state = { + article: {}, + mounted: false, + }; + + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Current problem'.toUpperCase(), + }; + + + componentWillMount() { + const articleId = this.props.navigation.getParam('id', 1); + console.log(articleId); + + axios.get(`http://192.168.1.43:8000/api/articles/${articleId}`) + .then(res => { + this.setState({ + article: res.data, + mounted: true, + }); + console.log(this.state.article); + }); + } + + render() { + if (this.state.mounted) { + return ( + <ScrollView style={styles.root}> + <RkCard rkType='article'> + <Image + rkCardImg + source={{ + uri: `${this.state.article.image.toString() + .replace('http://127.0.0.1:8000/', '')}`, + }} + /> + <View rkCardHeader> + <View> + <RkText style={styles.title} rkType='header4'>{this.state.article.title}</RkText> + </View> + + + </View> + <View rkCardContent> + <View> + <RkText rkType='primary3 bigLine'>{this.state.article.text}</RkText> + </View> + </View> + <View rkCardFooter> + <SocialBar comments={this.state.article.n_comments} is_solved={this.state.article.is_solved ? 'Solved' : "Doesn't solved"}/> + </View> + </RkCard> + </ScrollView> + + ); + } + return null; + } +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + title: { + marginBottom: 5, + }, +})); diff --git a/frontend/app/screens/articles/articles1.js b/frontend/app/screens/articles/articles1.js new file mode 100644 index 0000000..47049b4 --- /dev/null +++ b/frontend/app/screens/articles/articles1.js @@ -0,0 +1,74 @@ +import React from 'react'; +import { + FlatList, + Image, + View, + TouchableOpacity, +} from 'react-native'; +import { + RkText, + RkCard, RkStyleSheet, +} from 'react-native-ui-kitten'; +import { SocialBar } from '../../components'; +import { data } from '../../data'; +import NavigationType from '../../config/navigation/propTypes'; + +const moment = require('moment'); + +export class Articles1 extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Article List'.toUpperCase(), + }; + + state = { + data: data.getArticles(), + }; + + extractItemKey = (item) => `${item.id}`; + + onItemPressed = ({ item }) => { + this.props.navigation.navigate('Article', { id: item.id }); + }; + + renderItem = ({ item }) => ( + <TouchableOpacity + delayPressIn={70} + activeOpacity={0.8} + onPress={() => this.onItemPressed(item)}> + <RkCard rkType='backImg'> + <Image rkCardImg source={item.photo} /> + <View rkCardImgOverlay rkCardContent style={styles.overlay}> + <RkText rkType='header2 inverseColor'>{item.header}</RkText> + <RkText rkType='secondary2 inverseColor'>{moment().add(item.time, 'seconds').fromNow()}</RkText> + <View rkCardFooter style={styles.footer}> + <SocialBar rkType='leftAligned' /> + </View > + </View> + </RkCard> + </TouchableOpacity> + ); + + render = () => ( + <FlatList + data={this.state.data} + renderItem={this.renderItem} + keyExtractor={this.extractItemKey} + style={styles.root} + /> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + overlay: { + justifyContent: 'flex-end', + }, + footer: { + width: 240, + }, +})); diff --git a/frontend/app/screens/articles/articles2.js b/frontend/app/screens/articles/articles2.js new file mode 100644 index 0000000..0d48812 --- /dev/null +++ b/frontend/app/screens/articles/articles2.js @@ -0,0 +1,84 @@ +import React from 'react'; +import { + FlatList, + Image, + View, + TouchableOpacity, +} from 'react-native'; +import { + RkText, + RkCard, RkStyleSheet, +} from 'react-native-ui-kitten'; +import axios from 'axios'; +import { SocialBar } from '../../components'; +import NavigationType from '../../config/navigation/propTypes'; + + +export class Articles2 extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Problems List'.toUpperCase(), + }; + + state = { + articles: [], + }; + + componentDidMount() { + axios.get('http://192.168.1.43:8000/api/articles') + .then(res => { + this.setState({ + articles: res.data, + }); + + }); + } + + extractItemKey = (item) => `${item.id}`; + + onItemPressed = (item) => { + this.props.navigation.navigate('Article', { id: item.id }); + }; + + renderItem = ({ item }) => ( + <TouchableOpacity + delayPressIn={70} + activeOpacity={0.8} + onPress={() => this.onItemPressed(item)}> + <RkCard rkType='imgBlock' style={styles.card}> + <Image rkCardImg source={{ uri: `${item.image.toString().replace('http://127.0.0.1:8000/', '')}` }} /> + <View rkCardImgOverlay rkCardContent style={styles.overlay}> + <RkText rkType='header4 inverseColor'>{item.title}</RkText> + </View> + <View rkCardFooter> + <SocialBar rkType='space' showLabel likes={item.rating} comments={item.n_comments} is_solved={item.is_solved ? 'Solved' : "Doesn't solved"} /> + </View> + </RkCard> + </TouchableOpacity> + ); + + render = () => ( + <FlatList + data={this.state.articles} + renderItem={this.renderItem} + keyExtractor={this.extractItemKey} + style={styles.container} + /> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + container: { + backgroundColor: theme.colors.screen.scroll, + paddingVertical: 8, + paddingHorizontal: 14, + }, + card: { + marginVertical: 8, + }, + time: { + marginTop: 5, + }, +})); diff --git a/frontend/app/screens/articles/articles3.js b/frontend/app/screens/articles/articles3.js new file mode 100644 index 0000000..e5eda4e --- /dev/null +++ b/frontend/app/screens/articles/articles3.js @@ -0,0 +1,81 @@ +import React from 'react'; +import { + FlatList, + Image, + View, + TouchableOpacity, +} from 'react-native'; +import { + RkText, + RkCard, RkStyleSheet, +} from 'react-native-ui-kitten'; +import { SocialBar } from '../../components'; +import { data } from '../../data'; +import NavigationType from '../../config/navigation/propTypes'; + +const moment = require('moment'); + +export class Articles3 extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Article List'.toUpperCase(), + }; + + state = { + data: data.getArticles(), + }; + + extractItemKey = (item) => `${item.id}`; + + onItemPressed = ({ item }) => { + this.props.navigation.navigate('Article', { id: item.id }); + }; + + renderItem = ({ item }) => ( + <TouchableOpacity + delayPressIn={70} + activeOpacity={0.8} + onPress={() => this.onItemPressed(item)}> + <RkCard style={styles.card}> + <View rkCardHeader> + <View> + <RkText rkType='header4'>{item.header}</RkText> + <RkText rkType='secondary2 hintColor'>{moment().add(item.time, 'seconds').fromNow()}</RkText> + </View> + </View> + <Image rkCardImg source={item.photo} /> + <View style={styles.footer} rkCardFooter> + <SocialBar /> + </View > + </RkCard> + </TouchableOpacity> + ); + + render = () => ( + <FlatList + data={this.state.data} + renderItem={this.renderItem} + keyExtractor={this.extractItemKey} + style={styles.container} + /> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + container: { + backgroundColor: theme.colors.screen.scroll, + paddingHorizontal: 14, + paddingVertical: 8, + }, + card: { + marginVertical: 8, + }, + footer: { + paddingTop: 16, + }, + time: { + marginTop: 5, + }, +})); diff --git a/frontend/app/screens/articles/articles4.js b/frontend/app/screens/articles/articles4.js new file mode 100644 index 0000000..1f08ba1 --- /dev/null +++ b/frontend/app/screens/articles/articles4.js @@ -0,0 +1,78 @@ +import React from 'react'; +import { + FlatList, + Image, + View, + TouchableOpacity, +} from 'react-native'; +import { + RkText, + RkCard, + RkStyleSheet, +} from 'react-native-ui-kitten'; +import { SocialBar } from '../../components'; +import { data } from '../../data'; +import NavigationType from '../../config/navigation/propTypes'; + + +export class Articles4 extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Article List'.toUpperCase(), + }; + + state = { + data: data.getArticles(), + }; + + extractItemKey = (item) => `${item.id}`; + + renderItem = ({ item }) => ( + <TouchableOpacity + delayPressIn={70} + activeOpacity={0.8} + onPress={() => this.props.navigation.navigate('Article', { id: item.id })}> + <RkCard rkType='horizontal' style={styles.card}> + <Image rkCardImg source={item.photo} /> + <View rkCardContent> + <RkText numberOfLines={1} rkType='header6'>{item.header}</RkText> + <RkText rkType='secondary6 hintColor'> + {`${item.user.firstName} ${item.user.lastName}`} + </RkText> + <RkText style={styles.post} numberOfLines={2} rkType='secondary1'>{item.text}</RkText> + </View> + <View rkCardFooter> + <SocialBar rkType='space' showLabel /> + </View > + </RkCard> + </TouchableOpacity> + ); + + render = () => ( + <View> + <FlatList + data={this.state.data} + renderItem={this.renderItem} + keyExtractor={this.extractItemKey} + style={styles.container} + /> + </View> + ); +} + + +const styles = RkStyleSheet.create(theme => ({ + container: { + backgroundColor: theme.colors.screen.scroll, + paddingVertical: 8, + paddingHorizontal: 14, + }, + card: { + marginVertical: 8, + }, + post: { + marginTop: 13, + }, +})); diff --git a/frontend/app/screens/articles/blogposts.js b/frontend/app/screens/articles/blogposts.js new file mode 100644 index 0000000..3ce4565 --- /dev/null +++ b/frontend/app/screens/articles/blogposts.js @@ -0,0 +1,88 @@ +import React from 'react'; +import { + FlatList, + View, + Image, + TouchableOpacity, +} from 'react-native'; +import { + RkCard, RkStyleSheet, + RkText, +} from 'react-native-ui-kitten'; +import { Avatar } from '../../components'; +import { data } from '../../data'; +import NavigationType from '../../config/navigation/propTypes'; + +const moment = require('moment'); + +export class Blogposts extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Blogposts'.toUpperCase(), + }; + + state = { + data: data.getArticles('post'), + }; + + extractItemKey = (item) => `${item.id}`; + + onItemPressed = (item) => { + this.props.navigation.navigate('Article', { id: item.id }); + }; + + renderItem = ({ item }) => ( + <TouchableOpacity + delayPressIn={70} + activeOpacity={0.8} + onPress={() => this.onItemPressed(item)}> + <RkCard rkType='blog' style={styles.card}> + <Image rkCardImg source={item.photo} /> + <View rkCardHeader style={styles.content}> + <RkText style={styles.section} rkType='header4'>{item.title}</RkText> + </View> + <View rkCardContent> + <View> + <RkText rkType='primary3 mediumLine' numberOfLines={2}>{item.text}</RkText> + </View> + </View> + <View rkCardFooter> + <View style={styles.userInfo}> + <Avatar style={styles.avatar} rkType='circle small' img={item.user.photo} /> + <RkText rkType='header6'>{`${item.user.firstName} ${item.user.lastName}`}</RkText> + </View> + <RkText rkType='secondary2 hintColor'>{moment().add(item.time, 'seconds').fromNow()}</RkText> + </View> + </RkCard> + </TouchableOpacity> + ); + + render = () => ( + <FlatList + data={this.state.data} + renderItem={this.renderItem} + keyExtractor={this.extractItemKey} + style={styles.container} + /> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + container: { + backgroundColor: theme.colors.screen.scroll, + paddingVertical: 8, + paddingHorizontal: 14, + }, + card: { + marginVertical: 8, + }, + userInfo: { + flexDirection: 'row', + alignItems: 'center', + }, + avatar: { + marginRight: 17, + }, +})); diff --git a/frontend/app/screens/articles/index.js b/frontend/app/screens/articles/index.js new file mode 100644 index 0000000..115d2ac --- /dev/null +++ b/frontend/app/screens/articles/index.js @@ -0,0 +1,6 @@ +export * from './articles1'; +export * from './articles2'; +export * from './articles3'; +export * from './articles4'; +export * from './blogposts'; +export * from './article'; diff --git a/frontend/app/screens/dashboard/dashboard.js b/frontend/app/screens/dashboard/dashboard.js new file mode 100644 index 0000000..06c8d6a --- /dev/null +++ b/frontend/app/screens/dashboard/dashboard.js @@ -0,0 +1,117 @@ +import React from 'react'; +import { + View, + ScrollView, +} from 'react-native'; +import { + RkText, + RkStyleSheet, + RkTheme, +} from 'react-native-ui-kitten'; +import { FontAwesome } from '../../assets/icons'; +import { + ProgressChart, + DoughnutChart, + AreaChart, + AreaSmoothedChart, +} from '../../components/'; + +export class Dashboard extends React.Component { + static navigationOptions = { + title: 'Dashboard'.toUpperCase(), + }; + + state = { + data: { + statItems: [ + { + name: 'Stars', + value: '4,512', + icon: 'github', + background: RkTheme.current.colors.dashboard.stars, + }, + { + name: 'Tweets', + value: '2,256', + icon: 'twitter', + background: RkTheme.current.colors.dashboard.tweets, + }, + { + name: 'Likes', + value: '1,124', + icon: 'facebook', + background: RkTheme.current.colors.dashboard.likes, + }, + ], + }, + }; + + renderStatItem = (item) => ( + <View style={[styles.statItemContainer, { backgroundColor: item.background }]} key={item.name}> + <View> + <RkText rkType='header6' style={styles.statItemValue}>{item.value}</RkText> + <RkText rkType='secondary7' style={styles.statItemName}>{item.name}</RkText> + </View> + <RkText rkType='awesome hero' style={styles.statItemIcon}>{FontAwesome[item.icon]}</RkText> + </View> + ); + + render = () => { + const chartBackgroundStyle = { backgroundColor: RkTheme.current.colors.control.background }; + return ( + <ScrollView style={styles.screen}> + <View style={styles.statItems}> + {this.state.data.statItems.map(this.renderStatItem)} + </View> + <View style={[styles.chartBlock, chartBackgroundStyle]}> + <DoughnutChart /> + </View> + <View style={[styles.chartBlock, chartBackgroundStyle]}> + <AreaChart /> + </View> + <View style={[styles.chartBlock, chartBackgroundStyle]}> + <ProgressChart /> + </View> + <View style={[styles.chartBlock, chartBackgroundStyle]}> + <AreaSmoothedChart /> + </View> + </ScrollView> + ); + }; +} + +const styles = RkStyleSheet.create(theme => ({ + screen: { + backgroundColor: theme.colors.screen.scroll, + paddingHorizontal: 15, + }, + statItems: { + flexDirection: 'row', + justifyContent: 'space-between', + marginVertical: 15, + }, + statItemContainer: { + flexDirection: 'row', + justifyContent: 'space-between', + borderRadius: 3, + paddingHorizontal: 10, + paddingVertical: 10, + }, + statItemIcon: { + alignSelf: 'center', + marginLeft: 10, + color: 'white', + }, + statItemValue: { + color: 'white', + }, + statItemName: { + color: 'white', + }, + chartBlock: { + padding: 15, + marginBottom: 15, + justifyContent: 'center', + }, +})); + diff --git a/frontend/app/screens/dashboard/index.js b/frontend/app/screens/dashboard/index.js new file mode 100644 index 0000000..b58b6c9 --- /dev/null +++ b/frontend/app/screens/dashboard/index.js @@ -0,0 +1 @@ +export * from './dashboard'; diff --git a/frontend/app/screens/eCommerce/addToCardForm.js b/frontend/app/screens/eCommerce/addToCardForm.js new file mode 100644 index 0000000..5d41885 --- /dev/null +++ b/frontend/app/screens/eCommerce/addToCardForm.js @@ -0,0 +1,138 @@ +import React from 'react'; +import axios from 'axios'; +import { + View, + Keyboard, +} from 'react-native'; +import { + RkText, + RkTextInput, + RkStyleSheet, + RkAvoidKeyboard, +} from 'react-native-ui-kitten'; +import { GradientButton } from '../../components/'; +import { PasswordTextInput } from '../../components/passwordTextInput'; + +import { scale } from '../../utils/scale'; +import NavigationType from '../../config/navigation/propTypes'; + +export class AddToCardForm extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Add Card'.toUpperCase(), + }; + + state = { + name: '', + email: '', + problem: '', + + }; + + + onAddButtonPressed = () => { + axios.post('http://192.168.1.43:8000/api/articles/', { + title: this.state.problem.split(' ').slice(0, 5), + text: this.state.problem, + + }) + this.props.navigation.goBack(); + }; + + render = () => ( + <RkAvoidKeyboard + style={styles.screen} + onStartShouldSetResponder={() => true} + onResponderRelease={() => Keyboard.dismiss()}> + <View style={[styles.formContent]}> + <View> + + + <View style={[styles.content]}> + <View style={[styles.textRow]}> + <RkText rkType='subtitle'>Your name</RkText> + </View> + <RkTextInput + rkType='rounded' + onChangeText={(name) => this.setState({ name })} + value={this.state.name} + /> + </View> + + <View style={[styles.content]}> + <View style={[styles.textRow]}> + <RkText rkType='subtitle'>Your e-mail</RkText> + </View> + <RkTextInput + rkType='rounded' + onChangeText={(email) => this.setState({ email })} + value={this.state.email} + /> + </View> + + <View style={[styles.content]}> + <View style={[styles.textRow]}> + <RkText rkType='subtitle'>Describe eco-problem</RkText> + </View> + <RkTextInput + rkType='rounded' + onChangeText={(problem) => this.setState({ problem })} + value={this.state.problem} + /> + </View> + + + </View> + <View> + <GradientButton + rkType='large' + text='ADD TO CARD' + onPress={this.onAddButtonPressed} + /> + </View> + </View> + </RkAvoidKeyboard> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + screen: { + padding: 15, + flex: 1, + backgroundColor: theme.colors.screen.base, + }, + content: { + marginTop: 10, + }, + formContent: { + justifyContent: 'space-between', + flexDirection: 'column', + flex: 1, + }, + textRow: { + marginLeft: 20, + }, + expireDateBlock: { + justifyContent: 'space-between', + flexDirection: 'row', + }, + expireDateInput: { + flex: 0.48, + marginVertical: 10, + }, + expireDateInnerInput: { + textAlign: 'center', + }, + expireDateDelimiter: { + flex: 0.04, + }, + balloon: { + maxWidth: scale(250), + padding: 15, + borderRadius: 100, + borderWidth: 0.5, + borderColor: theme.colors.border.solid, + }, +})); diff --git a/frontend/app/screens/eCommerce/cards.js b/frontend/app/screens/eCommerce/cards.js new file mode 100644 index 0000000..c22c30d --- /dev/null +++ b/frontend/app/screens/eCommerce/cards.js @@ -0,0 +1,242 @@ +import React from 'react'; +import { + FlatList, + View, + Image, + TouchableOpacity, + Modal, +} from 'react-native'; +import { + RkText, + RkCard, + RkButton, + RkStyleSheet, + RkTheme, +} from 'react-native-ui-kitten'; +import { LinearGradient } from 'expo'; +import { data } from '../../data'; +import { PasswordTextInput } from '../../components/passwordTextInput'; +import { UIConstants } from '../../config/appConstants'; +import { scaleVertical } from '../../utils/scale'; + +export class Cards extends React.Component { + static navigationOptions = { + title: 'Cards'.toUpperCase(), + }; + + state = { + data: data.getCards(), + modalVisible: false, + }; + + getCardStyle = (type) => { + switch (type) { + case 'visa': + return { + gradient: RkTheme.current.colors.gradients.visa, + icon: require('../../assets/icons/visaIcon.png'), + }; + case 'mastercard': + return { + gradient: RkTheme.current.colors.gradients.mastercard, + icon: require('../../assets/icons/masterCardIcon.png'), + }; + case 'axp': + return { + gradient: RkTheme.current.colors.gradients.axp, + icon: require('../../assets/icons/americanExpressIcon.png'), + }; + default: return {}; + } + }; + + formatCurrency = (amount, currency) => { + switch (currency) { + case 'usd': + return `$${amount}`; + case 'eur': + return `€${amount}`; + default: return ''; + } + }; + + prepareCardNo = (cardNo) => { + const re = /\*+/; + const parts = cardNo.split(re); + return { + firstPart: parts[0], + lastPart: parts[1], + }; + }; + + renderFooter = () => ( + <View style={styles.footer}> + <RkButton style={styles.button} rkType='circle highlight'> + <Image source={require('../../assets/icons/iconPlus.png')} /> + </RkButton> + </View> + ); + + setModalVisible = (visible) => { + this.setState({ modalVisible: visible }); + }; + + onItemPressed = () => { + this.setModalVisible(true); + }; + + extractItemKey = (item) => `${item.id}`; + + renderItem = ({ item }) => { + const { gradient, icon } = this.getCardStyle(item.type); + const { firstPart, lastPart } = this.prepareCardNo(item.cardNo); + + return ( + <RkCard rkType='credit' style={styles.card}> + <TouchableOpacity + delayPressIn={70} + activeOpacity={0.8} + onPress={this.onItemPressed}> + <LinearGradient + colors={gradient} + start={{ x: 0.0, y: 0.5 }} + end={{ x: 1, y: 0.5 }} + style={styles.background}> + <View rkCardHeader> + <RkText rkType='header4 inverseColor'>{item.bank}</RkText> + <Image source={icon} /> + </View> + <View rkCardContent> + <View style={styles.cardNoContainer}> + <RkText style={styles.cardNo} rkType='header2 inverseColor'>{firstPart}</RkText> + <RkText style={[styles.cardNo, styles.cardPlaceholder]} rkType='header2 inverseColor'>* * * *</RkText> + <RkText style={[styles.cardNo, styles.cardPlaceholder]} rkType='header2 inverseColor'>* * * *</RkText> + <RkText style={styles.cardNo} rkType='header2 inverseColor'>{lastPart}</RkText> + </View> + <RkText style={styles.date} rkType='header6 inverseColor'>{item.date}</RkText> + </View> + <View rkCardFooter> + <View> + <RkText rkType='header4 inverseColor'>{item.currency.toUpperCase()}</RkText> + <RkText rkType='header6 inverseColor'>{item.name.toUpperCase()}</RkText> + </View> + <RkText + rkType='header2 inverseColor'>{this.formatCurrency(item.amount, item.currency)} + </RkText> + </View> + </LinearGradient> + </TouchableOpacity> + </RkCard> + ); + }; + + render = () => ( + <View style={styles.root}> + <FlatList + style={styles.list} + showsVerticalScrollIndicator={false} + ListFooterComponent={this.renderFooter} + keyExtractor={this.extractItemKey} + data={this.state.data} + renderItem={this.renderItem} + /> + <Modal + animationType="fade" + transparent + onRequestClose={() => this.setModalVisible(false)} + visible={this.state.modalVisible}> + <View style={styles.popupOverlay}> + <View style={styles.popup}> + <View style={styles.popupContent}> + <RkText style={styles.popupHeader} rkType='header4'>Enter security code</RkText> + <PasswordTextInput /> + </View> + <View style={styles.popupButtons}> + <RkButton + onPress={() => this.setModalVisible(false)} + style={styles.popupButton} + rkType='clear'> + <RkText rkType='light'>CANCEL</RkText> + </RkButton> + <View style={styles.separator} /> + <RkButton + onPress={() => this.setModalVisible(false)} + style={styles.popupButton} + rkType='clear'> + <RkText>OK</RkText> + </RkButton> + </View> + </View> + </View> + </Modal> + </View> + ) +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + list: { + marginHorizontal: 16, + }, + card: { + marginVertical: 8, + }, + background: { + borderRadius: 7, + }, + cardNoContainer: { + flexDirection: 'row', + }, + cardNo: { + marginHorizontal: 8, + }, + cardPlaceholder: { + paddingTop: 4, + }, + date: { + marginTop: scaleVertical(20), + }, + footer: { + marginTop: 8, + marginBottom: scaleVertical(16), + alignItems: 'center', + }, + button: { + height: 56, + width: 56, + }, + popup: { + backgroundColor: theme.colors.screen.base, + marginTop: scaleVertical(70), + marginHorizontal: 37, + borderRadius: 7, + }, + popupOverlay: { + backgroundColor: theme.colors.screen.overlay, + flex: 1, + marginTop: UIConstants.HeaderHeight, + }, + popupContent: { + alignItems: 'center', + margin: 16, + }, + popupHeader: { + marginBottom: scaleVertical(45), + }, + popupButtons: { + marginTop: 15, + flexDirection: 'row', + borderTopWidth: 1, + borderColor: theme.colors.border.base, + }, + popupButton: { + flex: 1, + marginVertical: 16, + }, + separator: { + backgroundColor: theme.colors.border.base, + width: 1, + }, +})); diff --git a/frontend/app/screens/eCommerce/index.js b/frontend/app/screens/eCommerce/index.js new file mode 100644 index 0000000..7658d81 --- /dev/null +++ b/frontend/app/screens/eCommerce/index.js @@ -0,0 +1,2 @@ +export * from './cards'; +export * from './addToCardForm'; diff --git a/frontend/app/screens/index.js b/frontend/app/screens/index.js new file mode 100644 index 0000000..b7ce1cb --- /dev/null +++ b/frontend/app/screens/index.js @@ -0,0 +1,11 @@ +export * from './navigation'; +export * from './menu'; +export * from './other'; +export * from './dashboard'; +export * from './social'; +export * from './articles'; +export * from './messaging'; +export * from './login'; +export * from './walkthroughs'; +export * from './eCommerce'; +export * from './theme'; diff --git a/frontend/app/screens/login/index.js b/frontend/app/screens/login/index.js new file mode 100644 index 0000000..b0b1cd1 --- /dev/null +++ b/frontend/app/screens/login/index.js @@ -0,0 +1,4 @@ +export * from './login1'; +export * from './login2'; +export * from './signUp'; +export * from './passwordRecovery'; diff --git a/frontend/app/screens/login/login1.js b/frontend/app/screens/login/login1.js new file mode 100644 index 0000000..73e97d5 --- /dev/null +++ b/frontend/app/screens/login/login1.js @@ -0,0 +1,129 @@ +import React from 'react'; +import { + View, + Image, + Dimensions, + Keyboard, +} from 'react-native'; +import { + RkButton, + RkText, + RkTextInput, + RkAvoidKeyboard, + RkStyleSheet, + RkTheme, +} from 'react-native-ui-kitten'; +import { FontAwesome } from '../../assets/icons'; +import { GradientButton } from '../../components/gradientButton'; +import { scaleModerate, scaleVertical } from '../../utils/scale'; +import NavigationType from '../../config/navigation/propTypes'; + +export class LoginV1 extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + header: null, + }; + + getThemeImageSource = (theme) => ( + theme.name === 'light' ? + require('../../assets/images/backgroundLoginV1.png') : require('../../assets/images/backgroundLoginV1DarkTheme.png') + ); + + renderImage = () => { + const screenSize = Dimensions.get('window'); + const imageSize = { + width: screenSize.width, + height: screenSize.height - scaleModerate(375, 1), + }; + return ( + <Image + style={[styles.image, imageSize]} + source={this.getThemeImageSource(RkTheme.current)} + /> + ); + }; + + onLoginButtonPressed = () => { + this.props.navigation.goBack(); + }; + + onSignUpButtonPressed = () => { + this.props.navigation.navigate('SignUp'); + }; + + render = () => ( + <RkAvoidKeyboard + onStartShouldSetResponder={() => true} + onResponderRelease={() => Keyboard.dismiss()} + style={styles.screen}> + {this.renderImage()} + <View style={styles.container}> + <View style={styles.buttons}> + <RkButton style={styles.button} rkType='social'> + <RkText rkType='awesome hero accentColor'>{FontAwesome.twitter}</RkText> + </RkButton> + <RkButton style={styles.button} rkType='social'> + <RkText rkType='awesome hero accentColor'>{FontAwesome.google}</RkText> + </RkButton> + <RkButton style={styles.button} rkType='social'> + <RkText rkType='awesome hero accentColor'>{FontAwesome.facebook}</RkText> + </RkButton> + </View> + <RkTextInput rkType='rounded' placeholder='Username' /> + <RkTextInput rkType='rounded' placeholder='Password' secureTextEntry /> + <GradientButton + style={styles.save} + rkType='large' + onPress={this.onLoginButtonPressed} + text='LOGIN' + /> + <View style={styles.footer}> + <View style={styles.textRow}> + <RkText rkType='primary3'>Don’t have an account?</RkText> + <RkButton rkType='clear'> + <RkText rkType='header6' onPress={this.onSignUpButtonPressed}>Sign up now</RkText> + </RkButton> + </View> + </View> + </View> + </RkAvoidKeyboard> + ) +} + +const styles = RkStyleSheet.create(theme => ({ + screen: { + flex: 1, + alignItems: 'center', + backgroundColor: theme.colors.screen.base, + }, + image: { + resizeMode: 'cover', + marginBottom: scaleVertical(10), + }, + container: { + paddingHorizontal: 17, + paddingBottom: scaleVertical(22), + alignItems: 'center', + flex: -1, + }, + footer: { + justifyContent: 'flex-end', + flex: 1, + }, + buttons: { + flexDirection: 'row', + marginBottom: scaleVertical(24), + }, + button: { + marginHorizontal: 14, + }, + save: { + marginVertical: 9, + }, + textRow: { + justifyContent: 'center', + flexDirection: 'row', + }, +})); diff --git a/frontend/app/screens/login/login2.js b/frontend/app/screens/login/login2.js new file mode 100644 index 0000000..c211190 --- /dev/null +++ b/frontend/app/screens/login/login2.js @@ -0,0 +1,127 @@ +import React from 'react'; +import { + View, + Image, + Keyboard, +} from 'react-native'; +import { + RkButton, + RkText, + RkTextInput, + RkAvoidKeyboard, + RkTheme, + RkStyleSheet, +} from 'react-native-ui-kitten'; +import { FontAwesome } from '../../assets/icons'; +import { GradientButton } from '../../components/gradientButton'; +import { scaleVertical } from '../../utils/scale'; +import NavigationType from '../../config/navigation/propTypes'; + +export class LoginV2 extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + header: null, + }; + + onLoginButtonPressed = () => { + this.props.navigation.goBack(); + }; + + onSignUpButtonPressed = () => { + this.props.navigation.navigate('SignUp'); + }; + + getThemeImageSource = (theme) => ( + theme.name === 'light' ? + require('../../assets/images/logo.png') : require('../../assets/images/logoDark.png') + ); + + renderImage = () => ( + <Image style={styles.image} source={this.getThemeImageSource(RkTheme.current)} /> + ); + + render = () => ( + <RkAvoidKeyboard + style={styles.screen} + onStartShouldSetResponder={() => true} + onResponderRelease={() => Keyboard.dismiss()}> + <View style={styles.header}> + {this.renderImage()} + <RkText rkType='light h1'>React Native</RkText> + <RkText rkType='logo h0'>UI Kitten</RkText> + </View> + <View style={styles.content}> + <View> + <RkTextInput rkType='rounded' placeholder='Username' /> + <RkTextInput rkType='rounded' placeholder='Password' secureTextEntry /> + <GradientButton + style={styles.save} + rkType='large' + text='LOGIN' + onPress={this.onLoginButtonPressed} + /> + </View> + <View style={styles.buttons}> + <RkButton style={styles.button} rkType='social'> + <RkText rkType='awesome hero'>{FontAwesome.twitter}</RkText> + </RkButton> + <RkButton style={styles.button} rkType='social'> + <RkText rkType='awesome hero'>{FontAwesome.google}</RkText> + </RkButton> + <RkButton style={styles.button} rkType='social'> + <RkText rkType='awesome hero'>{FontAwesome.facebook}</RkText> + </RkButton> + </View> + <View style={styles.footer}> + <View style={styles.textRow}> + <RkText rkType='primary3'>Don’t have an account?</RkText> + <RkButton rkType='clear' onPress={this.onSignUpButtonPressed}> + <RkText rkType='header6'>Sign up now</RkText> + </RkButton> + </View> + </View> + </View> + </RkAvoidKeyboard> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + screen: { + padding: scaleVertical(16), + flex: 1, + justifyContent: 'space-between', + backgroundColor: theme.colors.screen.base, + }, + image: { + height: scaleVertical(77), + resizeMode: 'contain', + }, + header: { + paddingBottom: scaleVertical(10), + alignItems: 'center', + justifyContent: 'center', + flex: 1, + }, + content: { + justifyContent: 'space-between', + }, + save: { + marginVertical: 20, + }, + buttons: { + flexDirection: 'row', + marginBottom: scaleVertical(24), + marginHorizontal: 24, + justifyContent: 'space-around', + }, + textRow: { + flexDirection: 'row', + justifyContent: 'center', + }, + button: { + borderColor: theme.colors.border.solid, + }, + footer: {}, +})); diff --git a/frontend/app/screens/login/passwordRecovery.js b/frontend/app/screens/login/passwordRecovery.js new file mode 100644 index 0000000..b383e4c --- /dev/null +++ b/frontend/app/screens/login/passwordRecovery.js @@ -0,0 +1,83 @@ +import React from 'react'; +import { + View, + Image, + Keyboard, +} from 'react-native'; +import { + RkStyleSheet, + RkText, + RkTextInput, + RkTheme, +} from 'react-native-ui-kitten'; +import { GradientButton } from '../../components/'; +import { scaleVertical } from '../../utils/scale'; +import NavigationType from '../../config/navigation/propTypes'; + +export class PasswordRecovery extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + header: null, + }; + + onSendButtonPressed = () => { + this.props.navigation.goBack(); + }; + + getThemeImageSource = (theme) => ( + theme.name === 'light' ? + require('../../assets/images/logo.png') : require('../../assets/images/logoDark.png') + ); + + renderImage = () => ( + <Image style={styles.image} source={this.getThemeImageSource(RkTheme.current)} /> + ); + + render = () => ( + <View + behavior='position' + style={styles.screen} + onStartShouldSetResponder={() => true} + onResponderRelease={() => Keyboard.dismiss()}> + <View style={styles.header}> + {this.renderImage()} + <RkText rkType='h1'>Password Recovery</RkText> + </View> + <View style={styles.content}> + <RkTextInput rkType='rounded' placeholder='Email' /> + <RkText rkType='secondary5 secondaryColor center'> + Enter your email below to receive your password reset instructions + </RkText> + </View> + <GradientButton + style={styles.save} + rkType='large' + text='SEND' + onPress={this.onSendButtonPressed} + /> + </View> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + screen: { + flex: 1, + paddingHorizontal: 16, + paddingVertical: scaleVertical(24), + justifyContent: 'space-between', + backgroundColor: theme.colors.screen.base, + }, + header: { + alignItems: 'center', + }, + image: { + marginVertical: scaleVertical(27), + height: scaleVertical(77), + resizeMode: 'contain', + }, + content: { + alignItems: 'center', + }, +})); diff --git a/frontend/app/screens/login/signUp.js b/frontend/app/screens/login/signUp.js new file mode 100644 index 0000000..5c7965e --- /dev/null +++ b/frontend/app/screens/login/signUp.js @@ -0,0 +1,110 @@ +import React from 'react'; +import { + View, + Image, + Keyboard, +} from 'react-native'; +import { + RkButton, + RkText, + RkTextInput, + RkStyleSheet, + RkTheme, + RkAvoidKeyboard, +} from 'react-native-ui-kitten'; +import { GradientButton } from '../../components/'; +import { scaleVertical } from '../../utils/scale'; +import NavigationType from '../../config/navigation/propTypes'; + +export class SignUp extends React.Component { + static navigationOptions = { + header: null, + }; + static propTypes = { + navigation: NavigationType.isRequired, + }; + + getThemeImageSource = (theme) => ( + theme.name === 'light' ? + require('../../assets/images/logo.png') : require('../../assets/images/logoDark.png') + ); + + renderImage = () => ( + <Image style={styles.image} source={this.getThemeImageSource(RkTheme.current)} /> + ); + + onSignUpButtonPressed = () => { + this.props.navigation.goBack(); + }; + + onSignInButtonPressed = () => { + this.props.navigation.navigate('Login1'); + }; + + render = () => ( + <RkAvoidKeyboard + style={styles.screen} + onStartShouldSetResponder={() => true} + onResponderRelease={() => Keyboard.dismiss()}> + <View style={{ alignItems: 'center' }}> + {this.renderImage()} + <RkText rkType='h1'>Registration</RkText> + </View> + <View style={styles.content}> + <View> + <RkTextInput rkType='rounded' placeholder='Name' /> + <RkTextInput rkType='rounded' placeholder='Email' /> + <RkTextInput rkType='rounded' placeholder='Password' secureTextEntry /> + <RkTextInput rkType='rounded' placeholder='Confirm Password' secureTextEntry /> + <GradientButton + style={styles.save} + rkType='large' + text='SIGN UP' + onPress={this.onSignUpButtonPressed} + /> + </View> + <View style={styles.footer}> + <View style={styles.textRow}> + <RkText rkType='primary3'>Already have an account?</RkText> + <RkButton rkType='clear' onPress={this.onSignInButtonPressed}> + <RkText rkType='header6'>Sign in now</RkText> + </RkButton> + </View> + </View> + </View> + </RkAvoidKeyboard> + ) +} + +const styles = RkStyleSheet.create(theme => ({ + screen: { + padding: 16, + flex: 1, + justifyContent: 'space-around', + backgroundColor: theme.colors.screen.base, + }, + image: { + marginBottom: 10, + height: scaleVertical(77), + resizeMode: 'contain', + }, + content: { + justifyContent: 'space-between', + }, + save: { + marginVertical: 20, + }, + buttons: { + flexDirection: 'row', + marginBottom: 24, + marginHorizontal: 24, + justifyContent: 'space-around', + }, + footer: { + justifyContent: 'flex-end', + }, + textRow: { + flexDirection: 'row', + justifyContent: 'center', + }, +})); diff --git a/frontend/app/screens/menu/categoryMenu.js b/frontend/app/screens/menu/categoryMenu.js new file mode 100644 index 0000000..6ed6400 --- /dev/null +++ b/frontend/app/screens/menu/categoryMenu.js @@ -0,0 +1,77 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { + TouchableHighlight, + View, + FlatList, + StyleSheet, +} from 'react-native'; +import { + RkStyleSheet, + RkTheme, + RkText, +} from 'react-native-ui-kitten'; +import NavigationType from '../../config/navigation/propTypes'; + +export class CategoryMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + items: PropTypes.arrayOf(PropTypes.shape({ + title: PropTypes.string.isRequired, + })).isRequired, + }; + + onItemPressed = (item) => { + const url = item.action || item.id; + this.props.navigation.navigate(url); + }; + + extractItemKey = (item) => item.id; + + renderItem = ({ item }) => ( + <TouchableHighlight + style={styles.item} + underlayColor={RkTheme.current.colors.button.underlay} + activeOpacity={1} + onPress={() => this.onItemPressed(item)}> + <View> + <RkText>{item.title}</RkText> + </View> + </TouchableHighlight> + ); + + renderPlaceholder = () => ( + <View style={styles.emptyContainer}> + <RkText rkType='light subtitle'>Coming Soon...</RkText> + </View> + ); + + renderList = () => ( + <FlatList + style={styles.list} + data={this.props.items} + keyExtractor={this.extractItemKey} + renderItem={this.renderItem} + /> + ); + + render = () => (this.props.items.length === 0 ? this.renderPlaceholder() : this.renderList()); +} + +const styles = RkStyleSheet.create(theme => ({ + item: { + paddingVertical: 32.5, + paddingHorizontal: 16.5, + borderBottomWidth: StyleSheet.hairlineWidth, + borderColor: theme.colors.border.base, + }, + list: { + backgroundColor: theme.colors.screen.base, + }, + emptyContainer: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + backgroundColor: theme.colors.screen.base, + }, +})); diff --git a/frontend/app/screens/menu/index.js b/frontend/app/screens/menu/index.js new file mode 100644 index 0000000..4bea133 --- /dev/null +++ b/frontend/app/screens/menu/index.js @@ -0,0 +1,2 @@ +export * from './categoryMenu'; +export * from './menus'; diff --git a/frontend/app/screens/menu/menus.js b/frontend/app/screens/menu/menus.js new file mode 100644 index 0000000..8cd8ff2 --- /dev/null +++ b/frontend/app/screens/menu/menus.js @@ -0,0 +1,114 @@ +/* eslint-disable react/no-multi-comp */ +import React from 'react'; + +import { CategoryMenu } from './categoryMenu'; +import * as Routes from '../../config/navigation/routesBuilder'; +import NavigationType from '../../config/navigation/propTypes'; + +export class LoginMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Login'.toUpperCase(), + }; + render = () => ( + <CategoryMenu navigation={this.props.navigation} items={Routes.LoginRoutes} /> + ); +} + +export class NavigationMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Navigation'.toUpperCase(), + }; + render = () => ( + <CategoryMenu navigation={this.props.navigation} items={Routes.NavigationRoutes} /> + ); +} + +export class SocialMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Social'.toUpperCase(), + }; + render = () => ( + <CategoryMenu navigation={this.props.navigation} items={Routes.SocialRoutes} /> + ); +} + +export class ArticleMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Articles'.toUpperCase(), + }; + render = () => ( + <CategoryMenu navigation={this.props.navigation} items={Routes.ArticleRoutes} /> + ); +} + +export class MessagingMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Messaging'.toUpperCase(), + }; + render = () => ( + <CategoryMenu navigation={this.props.navigation} items={Routes.MessagingRoutes} /> + ); +} + +export class DashboardMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Dashboards'.toUpperCase(), + }; + render = () => ( + <CategoryMenu navigation={this.props.navigation} items={Routes.DashboardRoutes} /> + ); +} + +export class WalkthroughMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Walkthrough'.toUpperCase(), + }; + render = () => ( + <CategoryMenu navigation={this.props.navigation} items={Routes.WalkthroughRoutes} /> + ); +} + +export class EcommerceMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Ecommerce'.toUpperCase(), + }; + render = () => ( + <CategoryMenu navigation={this.props.navigation} items={Routes.EcommerceRoutes} /> + ); +} + +export class OtherMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Other'.toUpperCase(), + }; + render = () => ( + <CategoryMenu navigation={this.props.navigation} items={Routes.OtherRoutes} /> + ); +} diff --git a/frontend/app/screens/messaging/chat.js b/frontend/app/screens/messaging/chat.js new file mode 100644 index 0000000..c6b0b5e --- /dev/null +++ b/frontend/app/screens/messaging/chat.js @@ -0,0 +1,214 @@ +import React from 'react'; +import { + FlatList, + View, + Platform, + Image, + TouchableOpacity, + Keyboard, + InteractionManager, +} from 'react-native'; +import { + RkButton, + RkText, + RkTextInput, + RkAvoidKeyboard, + RkStyleSheet, + RkTheme, +} from 'react-native-ui-kitten'; +import _ from 'lodash'; +import { FontAwesome } from '../../assets/icons'; +import { data } from '../../data'; +import { Avatar } from '../../components/avatar'; +import { scale } from '../../utils/scale'; +import NavigationType from '../../config/navigation/propTypes'; + +const moment = require('moment'); + +export class Chat extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = ({ navigation }) => { + const userId = navigation.state.params ? navigation.state.params.userId : undefined; + const user = data.getUser(userId); + return ({ + headerTitle: Chat.renderNavigationTitle(navigation, user), + headerRight: Chat.renderNavigationAvatar(navigation, user), + }); + }; + + constructor(props) { + super(props); + const userId = this.props.navigation.getParam('userId', undefined); + this.state = { + data: data.getConversation(userId), + }; + } + + componentDidMount() { + InteractionManager.runAfterInteractions(() => { + this.listRef.scrollToEnd(); + }); + } + + setListRef = (ref) => { + this.listRef = ref; + }; + + extractItemKey = (item) => `${item.id}`; + + scrollToEnd = () => { + if (Platform.OS === 'ios') { + this.listRef.scrollToEnd(); + } else { + _.delay(this.listRef.scrollToEnd, 100); + } + }; + + onInputChanged = (text) => { + this.setState({ message: text }); + }; + + onSendButtonPressed = () => { + if (!this.state.message) { + return; + } + this.state.data.messages.push({ + id: this.state.data.messages.length, time: 0, type: 'out', text: this.state.message, + }); + this.setState({ message: '' }); + this.scrollToEnd(true); + }; + + static onNavigationTitlePressed = (navigation, user) => { + navigation.navigate('ProfileV1', { id: user.id }); + }; + + static onNavigationAvatarPressed = (navigation, user) => { + navigation.navigate('ProfileV1', { id: user.id }); + }; + + static renderNavigationTitle = (navigation, user) => ( + <TouchableOpacity onPress={() => Chat.onNavigationTitlePressed(navigation, user)}> + <View style={styles.header}> + <RkText rkType='header5'>{`${user.firstName} ${user.lastName}`}</RkText> + <RkText rkType='secondary3 secondaryColor'>Online</RkText> + </View> + </TouchableOpacity> + ); + + static renderNavigationAvatar = (navigation, user) => ( + <TouchableOpacity onPress={() => Chat.onNavigationAvatarPressed(navigation, user)}> + <Avatar style={styles.avatar} rkType='small' img={user.photo} /> + </TouchableOpacity> + ); + + renderDate = (date) => ( + <RkText style={styles.time} rkType='secondary7 hintColor'> + {moment().add(date, 'seconds').format('LT')} + </RkText> + ); + + renderItem = ({ item }) => { + const isIncoming = item.type === 'in'; + const backgroundColor = isIncoming + ? RkTheme.current.colors.chat.messageInBackground + : RkTheme.current.colors.chat.messageOutBackground; + const itemStyle = isIncoming ? styles.itemIn : styles.itemOut; + + return ( + <View style={[styles.item, itemStyle]}> + {!isIncoming && this.renderDate(item.time)} + <View style={[styles.balloon, { backgroundColor }]}> + <RkText rkType='primary2 mediumLine chat' style={{ paddingTop: 5 }}>{item.text}</RkText> + </View> + {isIncoming && this.renderDate(item.time)} + </View> + ); + }; + + render = () => ( + <RkAvoidKeyboard + style={styles.container} + onResponderRelease={Keyboard.dismiss}> + <FlatList + ref={this.setListRef} + extraData={this.state} + style={styles.list} + data={this.state.data.messages} + keyExtractor={this.extractItemKey} + renderItem={this.renderItem} + /> + <View style={styles.footer}> + <RkButton style={styles.plus} rkType='clear'> + <RkText rkType='awesome secondaryColor'>{FontAwesome.plus}</RkText> + </RkButton> + <RkTextInput + onFocus={this.scrollToEnd} + onBlur={this.scrollToEnd} + onChangeText={this.onInputChanged} + value={this.state.message} + rkType='row sticker' + placeholder="Add a comment..." + /> + <RkButton onPress={this.onSendButtonPressed} style={styles.send} rkType='circle highlight'> + <Image source={require('../../assets/icons/sendIcon.png')} /> + </RkButton> + </View> + </RkAvoidKeyboard> + + ) +} + +const styles = RkStyleSheet.create(theme => ({ + header: { + alignItems: 'center', + }, + avatar: { + marginRight: 16, + }, + container: { + flex: 1, + backgroundColor: theme.colors.screen.base, + }, + list: { + paddingHorizontal: 17, + }, + footer: { + flexDirection: 'row', + minHeight: 60, + padding: 10, + backgroundColor: theme.colors.screen.alter, + }, + item: { + marginVertical: 14, + flex: 1, + flexDirection: 'row', + }, + itemIn: {}, + itemOut: { + alignSelf: 'flex-end', + }, + balloon: { + maxWidth: scale(250), + paddingHorizontal: 15, + paddingTop: 10, + paddingBottom: 15, + borderRadius: 20, + }, + time: { + alignSelf: 'flex-end', + margin: 15, + }, + plus: { + paddingVertical: 10, + paddingHorizontal: 10, + marginRight: 7, + }, + send: { + width: 40, + height: 40, + marginLeft: 10, + }, +})); diff --git a/frontend/app/screens/messaging/chatList.js b/frontend/app/screens/messaging/chatList.js new file mode 100644 index 0000000..36cde5c --- /dev/null +++ b/frontend/app/screens/messaging/chatList.js @@ -0,0 +1,147 @@ +import React from 'react'; +import { + FlatList, + View, + StyleSheet, + TouchableOpacity, +} from 'react-native'; +import _ from 'lodash'; +import { + RkStyleSheet, + RkText, + RkTextInput, +} from 'react-native-ui-kitten'; +import { Avatar } from '../../components'; +import { FontAwesome } from '../../assets/icons'; +import { data } from '../../data'; +import NavigationType from '../../config/navigation/propTypes'; + +const moment = require('moment'); + +export class ChatList extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Chats List'.toUpperCase(), + }; + + state = { + data: { + original: data.getChatList(), + filtered: data.getChatList(), + }, + }; + + extractItemKey = (item) => `${item.withUser.id}`; + + onInputChanged = (event) => { + const pattern = new RegExp(event.nativeEvent.text, 'i'); + const chats = _.filter(this.state.data.original, chat => { + const filterResult = { + firstName: chat.withUser.firstName.search(pattern), + lastName: chat.withUser.lastName.search(pattern), + }; + return filterResult.firstName !== -1 || filterResult.lastName !== -1 ? chat : undefined; + }); + this.setState({ + data: { + original: this.state.data.original, + filtered: chats, + }, + }); + }; + + onItemPressed = (item) => { + const navigationParams = { userId: item.withUser.id }; + this.props.navigation.navigate('Chat', navigationParams); + }; + + renderSeparator = () => ( + <View style={styles.separator} /> + ); + + renderInputLabel = () => ( + <RkText rkType='awesome'>{FontAwesome.search}</RkText> + ); + + renderHeader = () => ( + <View style={styles.searchContainer}> + <RkTextInput + autoCapitalize='none' + autoCorrect={false} + onChange={this.onInputChanged} + label={this.renderInputLabel()} + rkType='row' + placeholder='Search' + /> + </View> + ); + + renderItem = ({ item }) => { + const last = item.messages[item.messages.length - 1]; + return ( + <TouchableOpacity onPress={() => this.onItemPressed(item)}> + <View style={styles.container}> + <Avatar rkType='circle' style={styles.avatar} img={item.withUser.photo} /> + <View style={styles.content}> + <View style={styles.contentHeader}> + <RkText rkType='header5'>{`${item.withUser.firstName} ${item.withUser.lastName}`}</RkText> + <RkText rkType='secondary4 hintColor'> + {moment().add(last.time, 'seconds').format('LT')} + </RkText> + </View> + <RkText numberOfLines={2} rkType='primary3 mediumLine' style={{ paddingTop: 5 }}> + {last.text} + </RkText> + </View> + </View> + </TouchableOpacity> + ); + }; + + render = () => ( + <FlatList + style={styles.root} + data={this.state.data.filtered} + extraData={this.state} + ListHeaderComponent={this.renderHeader} + ItemSeparatorComponent={this.renderSeparator} + keyExtractor={this.extractItemKey} + renderItem={this.renderItem} + /> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + searchContainer: { + backgroundColor: theme.colors.screen.bold, + paddingHorizontal: 16, + paddingVertical: 10, + height: 60, + alignItems: 'center', + }, + container: { + paddingLeft: 19, + paddingRight: 16, + paddingBottom: 12, + paddingTop: 7, + flexDirection: 'row', + }, + content: { + marginLeft: 16, + flex: 1, + }, + contentHeader: { + flexDirection: 'row', + justifyContent: 'space-between', + marginBottom: 6, + }, + separator: { + height: StyleSheet.hairlineWidth, + backgroundColor: theme.colors.border.base, + }, +})); diff --git a/frontend/app/screens/messaging/comments.js b/frontend/app/screens/messaging/comments.js new file mode 100644 index 0000000..3b772c5 --- /dev/null +++ b/frontend/app/screens/messaging/comments.js @@ -0,0 +1,98 @@ +import React from 'react'; +import { + FlatList, + View, + StyleSheet, + TouchableOpacity, +} from 'react-native'; +import { + RkStyleSheet, + RkText, +} from 'react-native-ui-kitten'; +import { Avatar } from '../../components'; +import { data } from '../../data'; +import NavigationType from '../../config/navigation/propTypes'; + +const moment = require('moment'); + +export class Comments extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Comments'.toUpperCase(), + }; + + constructor(props) { + super(props); + const postId = this.props.navigation.getParam('postId', undefined); + this.state = { + data: data.getComments(postId), + }; + } + + extractItemKey = (item) => `${item.id}`; + + onItemPressed = (item) => { + const navigationParams = { id: item.user.id }; + this.props.navigation.navigate('ProfileV1', navigationParams); + }; + + renderSeparator = () => ( + <View style={styles.separator} /> + ); + + renderItem = ({ item }) => ( + <View style={styles.container}> + <TouchableOpacity onPress={() => this.onItemPressed(item)}> + <Avatar rkType='circle' style={styles.avatar} img={item.user.photo} /> + </TouchableOpacity> + <View style={styles.content}> + <View style={styles.contentHeader}> + <RkText rkType='header5'>{`${item.user.firstName} ${item.user.lastName}`}</RkText> + <RkText rkType='secondary4 hintColor'> + {moment().add(item.time, 'seconds').format('LT')} + </RkText> + </View> + <RkText rkType='primary3 mediumLine'>{item.text}</RkText> + </View> + </View> + ); + + render = () => ( + <FlatList + style={styles.root} + data={this.state.data} + extraData={this.state} + ItemSeparatorComponent={this.renderSeparator} + keyExtractor={this.extractItemKey} + renderItem={this.renderItem} + /> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + container: { + paddingLeft: 19, + paddingRight: 16, + paddingVertical: 12, + flexDirection: 'row', + alignItems: 'flex-start', + }, + content: { + marginLeft: 16, + flex: 1, + }, + contentHeader: { + flexDirection: 'row', + justifyContent: 'space-between', + marginBottom: 6, + }, + separator: { + height: StyleSheet.hairlineWidth, + backgroundColor: theme.colors.border.base, + }, +})); diff --git a/frontend/app/screens/messaging/index.js b/frontend/app/screens/messaging/index.js new file mode 100644 index 0000000..0d39244 --- /dev/null +++ b/frontend/app/screens/messaging/index.js @@ -0,0 +1,3 @@ +export * from './chat'; +export * from './chatList'; +export * from './comments'; diff --git a/frontend/app/screens/navigation/grid.js b/frontend/app/screens/navigation/grid.js new file mode 100644 index 0000000..7fbe404 --- /dev/null +++ b/frontend/app/screens/navigation/grid.js @@ -0,0 +1,70 @@ +import React from 'react'; +import { + ScrollView, + Dimensions, +} from 'react-native'; +import { + RkButton, RkStyleSheet, + RkText, +} from 'react-native-ui-kitten'; +import { MainRoutes } from '../../config/navigation/routes'; +import NavigationType from '../../config/navigation/propTypes'; + +const paddingValue = 8; + +export class GridV1 extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Grid Menu'.toUpperCase(), + }; + + constructor(props) { + super(props); + const screenWidth = Dimensions.get('window').width; + this.itemSize = { + width: (screenWidth - (paddingValue * 6)) / 2, + height: (screenWidth - (paddingValue * 6)) / 2, + }; + } + + onItemPressed = (item) => { + this.props.navigation.navigate(item.id); + }; + + renderItems = () => MainRoutes.map(route => ( + <RkButton + rkType='square shadow' + style={{ ...this.itemSize }} + key={route.id} + onPress={() => this.onItemPressed(route)}> + <RkText style={styles.icon} rkType='primary moon menuIcon'> + {route.icon} + </RkText> + <RkText>{route.title}</RkText> + </RkButton> + )); + + render = () => ( + <ScrollView + style={styles.root} + contentContainerStyle={styles.rootContainer}> + {this.renderItems()} + </ScrollView> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.scroll, + padding: paddingValue, + }, + rootContainer: { + flexDirection: 'row', + flexWrap: 'wrap', + }, + icon: { + marginBottom: 16, + }, +})); diff --git a/frontend/app/screens/navigation/grid2.js b/frontend/app/screens/navigation/grid2.js new file mode 100644 index 0000000..8773e02 --- /dev/null +++ b/frontend/app/screens/navigation/grid2.js @@ -0,0 +1,82 @@ +import React from 'react'; +import { + ScrollView, + View, + StyleSheet, +} from 'react-native'; +import { + RkText, + RkButton, + RkStyleSheet, +} from 'react-native-ui-kitten'; +import { MainRoutes } from '../../config/navigation/routes'; +import NavigationType from '../../config/navigation/propTypes'; + +export class GridV2 extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Grid Menu'.toUpperCase(), + }; + + state = { + dimensions: undefined, + }; + + onContainerLayout = (event) => { + if (this.state.height) { + return; + } + const dimensions = event.nativeEvent.layout; + this.setState({ dimensions }); + }; + + renderItems = () => MainRoutes.map(this.renderItem); + + renderItem = (item) => ( + <RkButton + rkType='tile' + style={{ height: this.state.dimensions.width / 3, width: this.state.dimensions.width / 3 }} + key={item.id} + onPress={() => this.onItemPressed(item)}> + <RkText style={styles.icon} rkType='primary moon xxlarge'> + {item.icon} + </RkText> + <RkText rkType='small'>{item.title}</RkText> + </RkButton> + ); + + onItemPressed = (item) => { + this.props.navigation.navigate(item.id); + }; + + render() { + const items = this.state.dimensions === undefined ? <View /> : this.renderItems(); + return ( + <ScrollView + style={styles.root} + onLayout={this.onContainerLayout} + contentContainerStyle={styles.rootContainer}> + {items} + </ScrollView> + ); + } +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + rootContainer: { + flexDirection: 'row', + flexWrap: 'wrap', + }, + empty: { + borderWidth: StyleSheet.hairlineWidth, + borderColor: theme.colors.border.base, + }, + icon: { + marginBottom: 16, + }, +})); diff --git a/frontend/app/screens/navigation/index.js b/frontend/app/screens/navigation/index.js new file mode 100644 index 0000000..3f5229f --- /dev/null +++ b/frontend/app/screens/navigation/index.js @@ -0,0 +1,4 @@ +export * from './grid2'; +export * from './grid'; +export * from './sideMenu'; +export * from './list'; diff --git a/frontend/app/screens/navigation/list.js b/frontend/app/screens/navigation/list.js new file mode 100644 index 0000000..33c52ba --- /dev/null +++ b/frontend/app/screens/navigation/list.js @@ -0,0 +1,73 @@ +import React from 'react'; +import { + FlatList, + TouchableOpacity, + View, + StyleSheet, +} from 'react-native'; +import { + RkText, + RkStyleSheet, +} from 'react-native-ui-kitten'; +import { MainRoutes } from '../../config/navigation/routes'; +import NavigationType from '../../config/navigation/propTypes'; + +export class ListMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'List Menu'.toUpperCase(), + }; + + onItemPressed = (item) => { + this.props.navigation.navigate(item.id); + }; + + extractItemKey = (item) => item.id; + + renderItem = ({ item }) => ( + <TouchableOpacity + style={styles.item} + onPress={() => this.onItemPressed(item)}> + <View style={styles.container}> + <RkText + style={styles.icon} + rkType='primary moon xxlarge'>{item.icon} + </RkText> + <RkText>{item.title}</RkText> + </View> + </TouchableOpacity> + ); + + render = () => ( + <FlatList + style={styles.list} + data={MainRoutes} + keyExtractor={this.extractItemKey} + renderItem={this.renderItem} + /> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + item: { + height: 80, + justifyContent: 'center', + borderBottomWidth: StyleSheet.hairlineWidth, + borderColor: theme.colors.border.base, + paddingHorizontal: 16, + }, + list: { + backgroundColor: theme.colors.screen.base, + }, + container: { + flexDirection: 'row', + alignItems: 'center', + }, + icon: { + width: 34, + textAlign: 'center', + marginRight: 16, + }, +})); diff --git a/frontend/app/screens/navigation/sideMenu.js b/frontend/app/screens/navigation/sideMenu.js new file mode 100644 index 0000000..7f5c5a1 --- /dev/null +++ b/frontend/app/screens/navigation/sideMenu.js @@ -0,0 +1,113 @@ +import React from 'react'; +import { + TouchableHighlight, + View, + ScrollView, + Image, + Platform, + StyleSheet, +} from 'react-native'; +import { + RkStyleSheet, + RkText, + RkTheme, +} from 'react-native-ui-kitten'; +import { MainRoutes } from '../../config/navigation/routes'; +import { FontAwesome, FontIcons } from '../../assets/icons'; +import NavigationType from '../../config/navigation/propTypes'; +import * as Screens from '../index'; + +export const NavbarRoutes = [ + { + id: 'Articles2', + title: 'Problems', + icon: FontIcons.article, + screen: Screens.Articles2, + + }, { + id: 'Login1', + title: 'Login', + icon: FontIcons.login, + screen: Screens.LoginV1, + + }, { + id: 'AddProblem', + title: 'Add Problem', + icon: FontIcons.article, + screen: Screens.AddToCardForm, + + }]; + +export class SideMenu extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + + onMenuItemPressed = (item) => { + this.props.navigation.navigate(item.id); + }; + + getThemeImageSource = (theme) => ( + theme.name === 'light' ? + require('../../assets/images/smallLogo.png') : require('../../assets/images/smallLogoDark.png') + ); + + renderIcon = () => ( + <Image style={styles.icon} source={this.getThemeImageSource(RkTheme.current)}/> + ); + + renderMenu = () => NavbarRoutes.map(this.renderMenuItem); + + renderMenuItem = (item) => ( + <TouchableHighlight + style={styles.container} + key={item.id} + underlayColor={RkTheme.current.colors.button.underlay} + activeOpacity={1} + onPress={() => this.onMenuItemPressed(item)}> + <View style={styles.content}> + <View style={styles.content}> + <RkText + style={styles.icon} + rkType='moon primary xlarge'>{item.icon} + </RkText> + <RkText>{item.title}</RkText> + </View> + <RkText rkType='awesome secondaryColor small'>{FontAwesome.chevronRight}</RkText> + </View> + </TouchableHighlight> + ); + + render = () => ( + <View style={styles.root}> + <ScrollView + showsVerticalScrollIndicator={false}> + <View style={[styles.container, styles.content]}> + <RkText rkType='logo'>EcoAlerts</RkText> + </View> + {this.renderMenu()} + </ScrollView> + </View> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + container: { + height: 80, + paddingHorizontal: 16, + borderTopWidth: StyleSheet.hairlineWidth, + borderColor: theme.colors.border.base, + }, + root: { + paddingTop: Platform.OS === 'ios' ? 20 : 0, + backgroundColor: theme.colors.screen.base, + }, + content: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + }, + icon: { + marginRight: 13, + }, +})); diff --git a/frontend/app/screens/other/index.js b/frontend/app/screens/other/index.js new file mode 100644 index 0000000..9784f88 --- /dev/null +++ b/frontend/app/screens/other/index.js @@ -0,0 +1,2 @@ +export * from './splash'; +export * from './settings'; diff --git a/frontend/app/screens/other/settings.js b/frontend/app/screens/other/settings.js new file mode 100644 index 0000000..910deb0 --- /dev/null +++ b/frontend/app/screens/other/settings.js @@ -0,0 +1,176 @@ +import React from 'react'; +import { + ScrollView, + View, + TouchableOpacity, + StyleSheet, +} from 'react-native'; +import { + RkText, + RkStyleSheet, + RkTheme, +} from 'react-native-ui-kitten'; +import { + RkSwitch, + FindFriends, +} from '../../components'; +import { FontAwesome } from '../../assets/icons'; + +export class Settings extends React.Component { + static navigationOptions = { + title: 'Settings'.toUpperCase(), + }; + + state = { + sendPush: true, + shouldRefresh: false, + twitterEnabled: true, + googleEnabled: false, + facebookEnabled: true, + }; + + onPushNotificationsSettingChanged = (value) => { + this.setState({ sendPush: value }); + }; + + onRefreshAutomaticallySettingChanged = (value) => { + this.setState({ shouldRefresh: value }); + }; + + onFindFriendsTwitterButtonPressed = () => { + this.setState({ twitterEnabled: !this.state.twitterEnabled }); + }; + + onFindFriendsGoogleButtonPressed = () => { + this.setState({ googleEnabled: !this.state.googleEnabled }); + }; + + onFindFriendsFacebookButtonPressed = () => { + this.setState({ facebookEnabled: !this.state.facebookEnabled }); + }; + + render = () => ( + <ScrollView style={styles.container}> + <View style={styles.section}> + <View style={[styles.row, styles.heading]}> + <RkText rkType='primary header6'>PROFILE SETTINGS</RkText> + </View> + <View style={styles.row}> + <TouchableOpacity style={styles.rowButton}> + <RkText rkType='header6'>Edit Profile</RkText> + </TouchableOpacity> + </View> + <View style={styles.row}> + <TouchableOpacity style={styles.rowButton}> + <RkText rkType='header6'>Change Password</RkText> + </TouchableOpacity> + </View> + <View style={styles.row}> + <RkText rkType='header6'>Send Push Notifications</RkText> + <RkSwitch + style={styles.switch} + value={this.state.sendPush} + name="Push" + onValueChange={this.onPushNotificationsSettingChanged} + /> + </View> + <View style={styles.row}> + <RkText rkType='header6'>Refresh Automatically</RkText> + <RkSwitch + style={styles.switch} + value={this.state.shouldRefresh} + name="Refresh" + onValueChange={this.onRefreshAutomaticallySettingChanged} + /> + </View> + </View> + <View style={styles.section}> + <View style={[styles.row, styles.heading]}> + <RkText rkType='primary header6'>FIND FRIENDS</RkText> + </View> + <View style={styles.row}> + <FindFriends + color={RkTheme.current.colors.twitter} + text='Twitter' + icon={FontAwesome.twitter} + selected={this.state.twitterEnabled} + onPress={this.onFindFriendsTwitterButtonPressed} + /> + </View> + <View style={styles.row}> + <FindFriends + color={RkTheme.current.colors.google} + text='Google' + icon={FontAwesome.google} + selected={this.state.googleEnabled} + onPress={this.onFindFriendsGoogleButtonPressed} + /> + </View> + <View style={styles.row}> + <FindFriends + color={RkTheme.current.colors.facebook} + text='Facebook' + icon={FontAwesome.facebook} + selected={this.state.facebookEnabled} + onPress={this.onFindFriendsFacebookButtonPressed} + /> + </View> + </View> + <View style={styles.section}> + <View style={[styles.row, styles.heading]}> + <RkText rkType='primary header6'>SUPPORT</RkText> + </View> + <View style={styles.row}> + <TouchableOpacity style={styles.rowButton}> + <RkText rkType='header6'>Help</RkText> + </TouchableOpacity> + </View> + <View style={styles.row}> + <TouchableOpacity style={styles.rowButton}> + <RkText rkType='header6'>Privacy Policy</RkText> + </TouchableOpacity> + </View> + <View style={styles.row}> + <TouchableOpacity style={styles.rowButton}> + <RkText rkType='header6'>Terms & Conditions</RkText> + </TouchableOpacity> + </View> + <View style={styles.row}> + <TouchableOpacity style={styles.rowButton}> + <RkText rkType='header6'>Logout</RkText> + </TouchableOpacity> + </View> + </View> + </ScrollView> + ) +} + +const styles = RkStyleSheet.create(theme => ({ + container: { + backgroundColor: theme.colors.screen.base, + }, + header: { + paddingVertical: 25, + }, + section: { + marginVertical: 25, + }, + heading: { + paddingBottom: 12.5, + }, + row: { + flexDirection: 'row', + justifyContent: 'space-between', + paddingHorizontal: 17.5, + borderBottomWidth: StyleSheet.hairlineWidth, + borderColor: theme.colors.border.base, + alignItems: 'center', + }, + rowButton: { + flex: 1, + paddingVertical: 24, + }, + switch: { + marginVertical: 14, + }, +})); diff --git a/frontend/app/screens/other/splash.js b/frontend/app/screens/other/splash.js new file mode 100644 index 0000000..33e7abe --- /dev/null +++ b/frontend/app/screens/other/splash.js @@ -0,0 +1,108 @@ +import React from 'react'; +import { + StyleSheet, + Image, + View, + Dimensions, + StatusBar, +} from 'react-native'; +import { + RkText, + RkTheme, +} from 'react-native-ui-kitten'; +import { + StackActions, + NavigationActions, +} from 'react-navigation'; +import { ProgressBar } from '../../components'; +import { KittenTheme } from '../../config/theme'; +import { scale, scaleVertical } from '../../utils/scale'; +import NavigationType from '../../config/navigation/propTypes'; + +const delay = 800; + +export class SplashScreen extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + state = { + progress: 0, + }; + + componentDidMount() { + StatusBar.setHidden(true, 'none'); + RkTheme.setTheme(KittenTheme); + this.timer = setInterval(this.updateProgress, delay); + } + + componentWillUnmount() { + clearInterval(this.timer); + } + + updateProgress = () => { + if (this.state.progress === 1) { + clearInterval(this.timer); + setTimeout(this.onLoaded, delay); + } else { + const randProgress = this.state.progress + (Math.random() * 0.5); + this.setState({ progress: randProgress > 1 ? 1 : randProgress }); + } + }; + + onLoaded = () => { + StatusBar.setHidden(false, 'slide'); + const toHome = StackActions.reset({ + index: 0, + actions: [NavigationActions.navigate({ routeName: 'Home' })], + }); + this.props.navigation.dispatch(toHome); + }; + + render = () => ( + <View style={styles.container}> + <View> + <Image + style={[styles.image, { width: Dimensions.get('window').width }]} + source={require('../../assets/images/splashBack.png')} + /> + <View style={styles.text}> + <RkText rkType='light' style={styles.hero}>EcoAlerts</RkText> + <RkText rkType='logo' style={styles.appName}>The best ecological problems coordinator</RkText> + </View> + </View> + <ProgressBar + color={RkTheme.current.colors.accent} + style={styles.progress} + progress={this.state.progress} + width={scale(320)} + /> + </View> + ); +} + +const styles = StyleSheet.create({ + container: { + backgroundColor: KittenTheme.colors.screen.base, + justifyContent: 'space-between', + flex: 1, + }, + image: { + resizeMode: 'cover', + height: scaleVertical(430), + }, + text: { + alignItems: 'center', + }, + hero: { + fontSize: 37, + }, + appName: { + textAlign: 'center', + fontSize: 33, + }, + progress: { + alignSelf: 'center', + marginBottom: 35, + backgroundColor: '#e5e5e5', + }, +}); diff --git a/frontend/app/screens/social/contacts.js b/frontend/app/screens/social/contacts.js new file mode 100644 index 0000000..8eaacae --- /dev/null +++ b/frontend/app/screens/social/contacts.js @@ -0,0 +1,124 @@ +import React from 'react'; +import { + FlatList, + View, + StyleSheet, + TouchableOpacity, +} from 'react-native'; +import _ from 'lodash'; +import { + RkStyleSheet, + RkText, + RkTextInput, +} from 'react-native-ui-kitten'; +import { data } from '../../data'; +import { Avatar } from '../../components/avatar'; +import { FontAwesome } from '../../assets/icons'; +import NavigationType from '../../config/navigation/propTypes'; + +export class Contacts extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'Contacts'.toUpperCase(), + }; + + state = { + data: { + original: data.getUsers(), + filtered: data.getUsers(), + }, + }; + + extractItemKey = (item) => `${item.id}`; + + onSearchInputChanged = (event) => { + const pattern = new RegExp(event.nativeEvent.text, 'i'); + const contacts = _.filter(this.state.data.original, contact => { + const filterResult = { + firstName: contact.firstName.search(pattern), + lastName: contact.lastName.search(pattern), + }; + return filterResult.firstName !== -1 || filterResult.lastName !== -1 ? contact : undefined; + }); + this.setState({ + data: { + original: this.state.data.original, + filtered: contacts, + }, + }); + }; + + onItemPressed = (item) => { + this.props.navigation.navigate('ProfileV1', { id: item.id }); + }; + + renderItem = ({ item }) => ( + <TouchableOpacity onPress={() => this.onItemPressed(item)}> + <View style={styles.container}> + <Avatar rkType='circle' style={styles.avatar} img={item.photo} /> + <RkText>{`${item.firstName} ${item.lastName}`}</RkText> + </View> + </TouchableOpacity> + ); + + renderSeparator = () => ( + <View style={styles.separator} /> + ); + + renderHeaderLabel = () => ( + <RkText rkType='awesome'>{FontAwesome.search}</RkText> + ); + + renderHeader = () => ( + <View style={styles.searchContainer}> + <RkTextInput + autoCapitalize='none' + autoCorrect={false} + onChange={this.onSearchInputChanged} + label={this.renderHeaderLabel()} + rkType='row' + placeholder='Search' + /> + </View> + ); + + render = () => ( + <FlatList + style={styles.root} + data={this.state.data.filtered} + renderItem={this.renderItem} + ListHeaderComponent={this.renderHeader} + ItemSeparatorComponent={this.renderSeparator} + keyExtractor={this.extractItemKey} + enableEmptySections + /> + ) +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + searchContainer: { + backgroundColor: theme.colors.screen.bold, + paddingHorizontal: 16, + paddingVertical: 10, + height: 60, + alignItems: 'center', + }, + container: { + flexDirection: 'row', + padding: 16, + alignItems: 'center', + }, + avatar: { + marginRight: 16, + }, + separator: { + flex: 1, + height: StyleSheet.hairlineWidth, + backgroundColor: theme.colors.border.base, + }, +})); diff --git a/frontend/app/screens/social/feed.js b/frontend/app/screens/social/feed.js new file mode 100644 index 0000000..3de46f2 --- /dev/null +++ b/frontend/app/screens/social/feed.js @@ -0,0 +1,73 @@ +import React from 'react'; +import { + FlatList, + View, + Image, +} from 'react-native'; +import { + RkCard, + RkText, RkStyleSheet, +} from 'react-native-ui-kitten'; +import { Avatar } from '../../components/avatar'; +import { SocialBar } from '../../components/socialBar'; +import { data } from '../../data'; + +const moment = require('moment'); + +export class Feed extends React.Component { + static navigationOptions = { + title: 'Feed'.toUpperCase(), + }; + + state = { + data: data.getArticles('post'), + }; + + extractItemKey = (item) => `${item.id}`; + + renderItem = ({ item }) => ( + <RkCard style={styles.card}> + <View rkCardHeader> + <Avatar + rkType='small' + style={styles.avatar} + img={item.user.photo} + /> + <View> + <RkText rkType='header4'>{`${item.user.firstName} ${item.user.lastName}`}</RkText> + <RkText rkType='secondary2 hintColor'>{moment().add(item.time, 'seconds').fromNow()}</RkText> + </View> + </View> + <Image rkCardImg source={item.photo} /> + <View rkCardContent> + <RkText rkType='primary3'>{item.text}</RkText> + </View> + <View rkCardFooter> + <SocialBar /> + </View > + </RkCard> + ); + + render = () => ( + <FlatList + data={this.state.data} + renderItem={this.renderItem} + keyExtractor={this.extractItemKey} + style={styles.container} + /> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + container: { + backgroundColor: theme.colors.screen.scroll, + paddingVertical: 8, + paddingHorizontal: 10, + }, + card: { + marginVertical: 8, + }, + avatar: { + marginRight: 16, + }, +})); diff --git a/frontend/app/screens/social/index.js b/frontend/app/screens/social/index.js new file mode 100644 index 0000000..bd66176 --- /dev/null +++ b/frontend/app/screens/social/index.js @@ -0,0 +1,7 @@ +export * from './profile1'; +export * from './profile2'; +export * from './profile3'; +export * from './profileSettings'; +export * from './notifications'; +export * from './contacts'; +export * from './feed'; diff --git a/frontend/app/screens/social/notifications.js b/frontend/app/screens/social/notifications.js new file mode 100644 index 0000000..c397d17 --- /dev/null +++ b/frontend/app/screens/social/notifications.js @@ -0,0 +1,98 @@ +import React from 'react'; +import { + FlatList, + View, + Image, +} from 'react-native'; +import { RkStyleSheet, RkText } from 'react-native-ui-kitten'; +import { Avatar } from '../../components'; +import { data } from '../../data'; + +const moment = require('moment'); + +export class Notifications extends React.Component { + static navigationOptions = { + title: 'Notifications', + }; + + state = { + data: data.getNotifications(), + }; + + extractItemKey = (item) => `${item.id}`; + + renderAttachment = (item) => { + const hasAttachment = item.attach !== undefined; + return hasAttachment ? <View /> : <Image style={styles.attachment} source={item.attach} />; + }; + + renderItem = ({ item }) => ( + <View style={styles.container}> + <Avatar + img={item.user.photo} + rkType='circle' + style={styles.avatar} + badge={item.type} + /> + <View style={styles.content}> + <View style={styles.mainContent}> + <View style={styles.text}> + <RkText> + <RkText rkType='header6'>{`${item.user.firstName} ${item.user.lastName}`}</RkText> + <RkText rkType='primary2'> {item.description}</RkText> + </RkText> + </View> + <RkText + rkType='secondary5 hintColor'>{moment().add(item.time, 'seconds').fromNow()} + </RkText> + </View> + {this.renderAttachment(item)} + </View> + </View> + ); + + render = () => ( + <FlatList + style={styles.root} + data={this.state.data} + renderItem={this.renderItem} + keyExtractor={this.extractItemKey} + /> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + container: { + padding: 16, + flexDirection: 'row', + borderBottomWidth: 1, + borderColor: theme.colors.border.base, + alignItems: 'flex-start', + }, + avatar: {}, + text: { + marginBottom: 5, + }, + content: { + flex: 1, + marginLeft: 16, + marginRight: 0, + }, + mainContent: { + marginRight: 60, + }, + img: { + height: 50, + width: 50, + margin: 0, + }, + attachment: { + position: 'absolute', + right: 0, + height: 50, + width: 50, + }, +})); diff --git a/frontend/app/screens/social/profile1.js b/frontend/app/screens/social/profile1.js new file mode 100644 index 0000000..1f3ec09 --- /dev/null +++ b/frontend/app/screens/social/profile1.js @@ -0,0 +1,104 @@ +import React from 'react'; +import { + View, + ScrollView, +} from 'react-native'; +import { + RkText, + RkButton, RkStyleSheet, +} from 'react-native-ui-kitten'; +import { Avatar } from '../../components/avatar'; +import { Gallery } from '../../components/gallery'; +import { data } from '../../data/'; +import formatNumber from '../../utils/textUtils'; +import NavigationType from '../../config/navigation/propTypes'; + +export class ProfileV1 extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + title: 'User Profile'.toUpperCase(), + }; + + state = { + data: undefined, + }; + + constructor(props) { + super(props); + const id = this.props.navigation.getParam('id', 1); + this.state.data = data.getUser(id); + } + + render = () => ( + <ScrollView style={styles.root}> + <View style={[styles.header, styles.bordered]}> + <Avatar img={this.state.data.photo} rkType='big' /> + <RkText rkType='header2'>{`${this.state.data.firstName} ${this.state.data.lastName}`}</RkText> + </View> + <View style={[styles.userInfo, styles.bordered]}> + <View style={styles.section}> + <RkText rkType='header3' style={styles.space}>{this.state.data.postCount}</RkText> + <RkText rkType='secondary1 hintColor'>Posts</RkText> + </View> + <View style={styles.section}> + <RkText rkType='header3' style={styles.space}>{formatNumber(this.state.data.followersCount)}</RkText> + <RkText rkType='secondary1 hintColor'>Followers</RkText> + </View> + <View style={styles.section}> + <RkText rkType='header3' style={styles.space}>{this.state.data.followingCount}</RkText> + <RkText rkType='secondary1 hintColor'>Following</RkText> + </View> + </View> + <View style={styles.buttons}> + <RkButton style={styles.button} rkType='clear link'>FOLLOW</RkButton> + <View style={styles.separator} /> + <RkButton style={styles.button} rkType='clear link'>MESSAGE</RkButton> + </View> + <Gallery items={this.state.data.images} /> + </ScrollView> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + header: { + alignItems: 'center', + paddingTop: 25, + paddingBottom: 17, + }, + userInfo: { + flexDirection: 'row', + paddingVertical: 18, + }, + bordered: { + borderBottomWidth: 1, + borderColor: theme.colors.border.base, + }, + section: { + flex: 1, + alignItems: 'center', + }, + space: { + marginBottom: 3, + }, + separator: { + backgroundColor: theme.colors.border.base, + alignSelf: 'center', + flexDirection: 'row', + flex: 0, + width: 1, + height: 42, + }, + buttons: { + flexDirection: 'row', + paddingVertical: 8, + }, + button: { + flex: 1, + alignSelf: 'center', + }, +})); diff --git a/frontend/app/screens/social/profile2.js b/frontend/app/screens/social/profile2.js new file mode 100644 index 0000000..1636910 --- /dev/null +++ b/frontend/app/screens/social/profile2.js @@ -0,0 +1,108 @@ +import React from 'react'; +import { + View, + ScrollView, +} from 'react-native'; +import { + RkText, + RkButton, RkStyleSheet, +} from 'react-native-ui-kitten'; +import { + Avatar, + Gallery, +} from '../../components'; +import { data } from '../../data'; +import { FontIcons } from '../../assets/icons'; +import formatNumber from '../../utils/textUtils'; + +export class ProfileV2 extends React.Component { + static navigationOptions = { + title: 'User Profile'.toUpperCase(), + }; + + state = { + data: data.getUser(), + }; + + render = () => ( + <ScrollView style={styles.root}> + <View style={[styles.header, styles.bordered]}> + <View style={styles.row}> + <View style={styles.buttons}> + <RkButton style={styles.button} rkType='icon circle'> + <RkText rkType='moon large primary'>{FontIcons.profile}</RkText> + </RkButton> + </View> + <Avatar img={this.state.data.photo} rkType='big' /> + <View style={styles.buttons}> + <RkButton style={styles.button} rkType='icon circle'> + <RkText rkType='moon large primary'>{FontIcons.mail}</RkText> + </RkButton> + </View> + </View> + <View style={styles.section}> + <RkText rkType='header2'>{`${this.state.data.firstName} ${this.state.data.lastName}`}</RkText> + </View> + </View> + <View style={styles.userInfo}> + <View style={styles.section}> + <RkText rkType='header3' style={styles.space}>{this.state.data.postCount}</RkText> + <RkText rkType='secondary1 hintColor'>Posts</RkText> + </View> + <View style={styles.section}> + <RkText rkType='header3' style={styles.space}>{formatNumber(this.state.data.followersCount)}</RkText> + <RkText rkType='secondary1 hintColor'>Followers</RkText> + </View> + <View style={styles.section}> + <RkText rkType='header3' style={styles.space}>{this.state.data.followingCount}</RkText> + <RkText rkType='secondary1 hintColor'>Following</RkText> + </View> + </View> + <Gallery items={this.state.data.images} /> + </ScrollView> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + header: { + paddingTop: 25, + paddingBottom: 17, + }, + row: { + flexDirection: 'row', + + }, + userInfo: { + flexDirection: 'row', + paddingVertical: 18, + }, + bordered: { + borderBottomWidth: 1, + borderColor: theme.colors.border.base, + }, + section: { + flex: 1, + alignItems: 'center', + }, + space: { + marginBottom: 3, + }, + separator: { + backgroundColor: theme.colors.border.base, + alignSelf: 'center', + flexDirection: 'row', + flex: 0, + width: 1, + height: 42, + }, + buttons: { + flex: 1, + }, + button: { + marginTop: 27.5, + alignSelf: 'center', + }, +})); diff --git a/frontend/app/screens/social/profile3.js b/frontend/app/screens/social/profile3.js new file mode 100644 index 0000000..985dc1e --- /dev/null +++ b/frontend/app/screens/social/profile3.js @@ -0,0 +1,96 @@ +import React from 'react'; +import { + View, + ScrollView, +} from 'react-native'; +import { + RkStyleSheet, + RkText, +} from 'react-native-ui-kitten'; +import { + Avatar, + Gallery, + GradientButton, +} from '../../components'; +import { data } from '../../data'; +import formatNumber from '../../utils/textUtils'; + +export class ProfileV3 extends React.Component { + static navigationOptions = { + title: 'User Profile'.toUpperCase(), + }; + + state = { + data: data.getUser(), + }; + + render = () => ( + <ScrollView style={styles.root}> + <View style={[styles.header, styles.bordered]}> + <Avatar img={this.state.data.photo} rkType='big' /> + <RkText rkType='header2'>{`${this.state.data.firstName} ${this.state.data.lastName}`}</RkText> + <GradientButton style={styles.button} text='FOLLOW' /> + </View> + + <View style={styles.userInfo}> + <View style={styles.section}> + <RkText rkType='header3' style={styles.space}>{this.state.data.postCount}</RkText> + <RkText rkType='secondary1 hintColor'>Posts</RkText> + </View> + <View style={styles.section}> + <RkText rkType='header3' style={styles.space}>{formatNumber(this.state.data.followersCount)}</RkText> + <RkText rkType='secondary1 hintColor'>Followers</RkText> + </View> + <View style={styles.section}> + <RkText rkType='header3' style={styles.space}>{this.state.data.followingCount}</RkText> + <RkText rkType='secondary1 hintColor'>Following</RkText> + </View> + </View> + <Gallery items={this.state.data.images} /> + </ScrollView> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + header: { + alignItems: 'center', + paddingTop: 25, + paddingBottom: 17, + }, + userInfo: { + flexDirection: 'row', + paddingVertical: 18, + }, + bordered: { + borderBottomWidth: 1, + borderColor: theme.colors.border.base, + }, + section: { + flex: 1, + alignItems: 'center', + }, + space: { + marginBottom: 3, + }, + separator: { + backgroundColor: theme.colors.border.base, + alignSelf: 'center', + flexDirection: 'row', + flex: 0, + width: 1, + height: 42, + }, + buttons: { + flexDirection: 'row', + paddingVertical: 8, + }, + button: { + marginTop: 18, + alignSelf: 'center', + width: 140, + }, + +})); diff --git a/frontend/app/screens/social/profileSettings.js b/frontend/app/screens/social/profileSettings.js new file mode 100644 index 0000000..0be1b94 --- /dev/null +++ b/frontend/app/screens/social/profileSettings.js @@ -0,0 +1,200 @@ +import React from 'react'; +import { + ScrollView, + View, + StyleSheet, +} from 'react-native'; +import { + RkText, + RkTextInput, + RkAvoidKeyboard, + RkTheme, + RkStyleSheet, +} from 'react-native-ui-kitten'; +import { data } from '../../data'; +import { + Avatar, + SocialSetting, + GradientButton, +} from '../../components'; +import { FontAwesome } from '../../assets/icons'; + +export class ProfileSettings extends React.Component { + static navigationOptions = { + title: 'Profile Settings'.toUpperCase(), + }; + + user = data.getUser(); + + state = { + firstName: this.user.firstName, + lastName: this.user.lastName, + email: this.user.email, + country: this.user.country, + phone: this.user.phone, + password: this.user.password, + newPassword: this.user.newPassword, + confirmPassword: this.user.confirmPassword, + }; + + onFirstNameInputChanged = (text) => { + this.setState({ firstName: text }); + }; + + onLastNameInputChanged = (text) => { + this.setState({ lastName: text }); + }; + + onEmailInputChanged = (text) => { + this.setState({ email: text }); + }; + + onCountryInputChanged = (text) => { + this.setState({ country: text }); + }; + + onPhoneInputChanged = (text) => { + this.setState({ phone: text }); + }; + + onPasswordInputChanged = (text) => { + this.setState({ password: text }); + }; + + onNewPasswordInputChanged = (text) => { + this.setState({ newPassword: text }); + }; + + onConfirmPasswordInputChanged = (text) => { + this.setState({ confirmPassword: text }); + }; + + render = () => ( + <ScrollView style={styles.root}> + <RkAvoidKeyboard> + <View style={styles.header}> + <Avatar img={this.user.photo} rkType='big' /> + </View> + <View style={styles.section}> + <View style={[styles.row, styles.heading]}> + <RkText rkType='header6 primary'>INFO</RkText> + </View> + <View style={styles.row}> + <RkTextInput + label='First Name' + value={this.state.firstName} + rkType='right clear' + onChangeText={this.onFirstNameInputChanged} + /> + </View> + <View style={styles.row}> + <RkTextInput + label='Last Name' + value={this.state.lastName} + onChangeText={this.onLastNameInputChanged} + rkType='right clear' + /> + </View> + <View style={styles.row}> + <RkTextInput + label='Email' + value={this.state.email} + onChangeText={this.onEmailInputChanged} + rkType='right clear' + /> + </View> + <View style={styles.row}> + <RkTextInput + label='Country' + value={this.state.country} + onChangeText={this.onCountryInputChanged} + rkType='right clear' + /> + </View> + <View style={styles.row}> + <RkTextInput + label='Phone' + value={this.state.phone} + onChangeText={this.onPhoneInputChanged} + rkType='right clear' + /> + </View> + </View> + <View style={styles.section}> + <View style={[styles.row, styles.heading]}> + <RkText rkType='primary header6'>CHANGE PASSWORD</RkText> + </View> + <View style={styles.row}> + <RkTextInput + label='Old Password' + value={this.state.password} + rkType='right clear' + secureTextEntry + onChangeText={this.onPasswordInputChanged} + /> + </View> + <View style={styles.row}> + <RkTextInput + label='New Password' + value={this.state.newPassword} + rkType='right clear' + secureTextEntry + onChangeText={this.onNewPasswordInputChanged} + /> + </View> + <View style={styles.row}> + <RkTextInput + label='Confirm Password' + value={this.state.confirmPassword} + rkType='right clear' + secureTextEntry + onChangeText={this.onConfirmPasswordInputChanged} + /> + </View> + </View> + <View style={styles.section}> + <View style={[styles.row, styles.heading]}> + <RkText rkType='primary header6'>CONNECT YOUR ACCOUNT</RkText> + </View> + <View style={styles.row}> + <SocialSetting name='Twitter' icon={FontAwesome.twitter} tintColor={RkTheme.current.colors.twitter} /> + </View> + <View style={styles.row}> + <SocialSetting name='Google' icon={FontAwesome.google} tintColor={RkTheme.current.colors.google} /> + </View> + <View style={styles.row}> + <SocialSetting name='Facebook' icon={FontAwesome.facebook} tintColor={RkTheme.current.colors.facebook} /> + </View> + </View> + <GradientButton rkType='large' style={styles.button} text='SAVE' /> + </RkAvoidKeyboard> + </ScrollView> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + }, + header: { + backgroundColor: theme.colors.screen.neutral, + paddingVertical: 25, + }, + section: { + marginVertical: 25, + }, + heading: { + paddingBottom: 12.5, + }, + row: { + flexDirection: 'row', + paddingHorizontal: 17.5, + borderBottomWidth: StyleSheet.hairlineWidth, + borderColor: theme.colors.border.base, + alignItems: 'center', + }, + button: { + marginHorizontal: 16, + marginBottom: 32, + }, +})); diff --git a/frontend/app/screens/theme/index.js b/frontend/app/screens/theme/index.js new file mode 100644 index 0000000..22cacb2 --- /dev/null +++ b/frontend/app/screens/theme/index.js @@ -0,0 +1 @@ +export * from './themes'; diff --git a/frontend/app/screens/theme/themes.js b/frontend/app/screens/theme/themes.js new file mode 100644 index 0000000..82f4165 --- /dev/null +++ b/frontend/app/screens/theme/themes.js @@ -0,0 +1,77 @@ +import React from 'react'; +import { + View, + Image, + StatusBar, + Platform, +} from 'react-native'; +import { + RkText, + RkTheme, + RkStyleSheet, +} from 'react-native-ui-kitten'; +import { DarkKittenTheme } from '../../config/darkTheme'; +import { KittenTheme } from '../../config/theme'; +import { GradientButton } from '../../components/gradientButton'; +import { scale, scaleVertical } from '../../utils/scale'; + +export class Themes extends React.Component { + static navigationOptions = { + title: 'Theme'.toUpperCase(), + }; + + onLightThemeApplyButtonPressed = () => { + StatusBar.setBarStyle('dark-content', true); + if (Platform.OS === 'android') { + StatusBar.setBackgroundColor(KittenTheme.colors.screen.base); + } + RkTheme.setTheme(KittenTheme); + }; + + onDarkThemeApplyButtonPressed = () => { + StatusBar.setBarStyle('light-content', true); + if (Platform.OS === 'android') { + StatusBar.setBackgroundColor(DarkKittenTheme.colors.screen.base); + } + RkTheme.setTheme(DarkKittenTheme); + }; + + render = () => ( + <View style={styles.root}> + <View style={styles.container}> + <RkText>Light Theme</RkText> + <Image style={styles.image} source={require('../../assets/images/lightThemeImage.png')} /> + <GradientButton + text='APPLY' + onPress={this.onLightThemeApplyButtonPressed} + /> + </View> + <View style={styles.container}> + <RkText>Dark Theme</RkText> + <Image style={styles.image} source={require('../../assets/images/darkThemeImage.png')} /> + <GradientButton + text='APPLY' + onPress={this.onDarkThemeApplyButtonPressed} + /> + </View> + </View> + ); +} + +const styles = RkStyleSheet.create(theme => ({ + root: { + backgroundColor: theme.colors.screen.base, + flex: 1, + paddingHorizontal: scale(72), + + }, + image: { + height: scaleVertical(160), + }, + container: { + flex: 1, + alignItems: 'center', + justifyContent: 'space-between', + paddingVertical: scaleVertical(20), + }, +})); diff --git a/frontend/app/screens/walkthroughs/index.js b/frontend/app/screens/walkthroughs/index.js new file mode 100644 index 0000000..e7f1eb0 --- /dev/null +++ b/frontend/app/screens/walkthroughs/index.js @@ -0,0 +1 @@ +export * from './walkthroughScreen'; diff --git a/frontend/app/screens/walkthroughs/walkthrough1.js b/frontend/app/screens/walkthroughs/walkthrough1.js new file mode 100644 index 0000000..2f08f97 --- /dev/null +++ b/frontend/app/screens/walkthroughs/walkthrough1.js @@ -0,0 +1,40 @@ +import React from 'react'; +import { + View, + Image, +} from 'react-native'; +import { + RkText, + RkStyleSheet, + RkTheme, +} from 'react-native-ui-kitten'; + +export class Walkthrough1 extends React.Component { + getThemeImageSource = (theme) => ( + theme.name === 'light' ? + require('../../assets/images/kittenImage.png') : require('../../assets/images/kittenImageDark.png') + ); + + renderImage = () => ( + <Image source={this.getThemeImageSource(RkTheme.current)} /> + ); + + render = () => ( + <View style={styles.screen}> + {this.renderImage()} + <RkText rkType='header2' style={styles.text}>Welcome to EcoAlerts</RkText> + </View> + ) +} + +const styles = RkStyleSheet.create(theme => ({ + screen: { + backgroundColor: theme.colors.screen.base, + alignItems: 'center', + justifyContent: 'center', + flex: 1, + }, + text: { + marginTop: 20, + }, +})); diff --git a/frontend/app/screens/walkthroughs/walkthrough2.js b/frontend/app/screens/walkthroughs/walkthrough2.js new file mode 100644 index 0000000..6e387b8 --- /dev/null +++ b/frontend/app/screens/walkthroughs/walkthrough2.js @@ -0,0 +1,46 @@ +import React from 'react'; +import { + View, + Image, + Dimensions, +} from 'react-native'; +import { + RkText, + RkStyleSheet, + RkTheme, +} from 'react-native-ui-kitten'; + +export class Walkthrough2 extends React.Component { + getThemeImageSource = (theme) => ( + theme.name === 'light' ? + require('../../assets/images/screensImage.png') : require('../../assets/images/screensImageDark.png') + ); + + renderImage = () => ( + <Image + style={{ width: Dimensions.get('window').width }} + source={this.getThemeImageSource(RkTheme.current)} + /> + ); + + render = () => ( + <View style={styles.screen}> + {this.renderImage()} + <RkText rkType='header2' style={styles.text}>Share info about ecological problems around!</RkText> + </View> + ) +} + +const styles = RkStyleSheet.create(theme => ({ + screen: { + backgroundColor: theme.colors.screen.base, + alignItems: 'center', + justifyContent: 'center', + flex: 1, + }, + text: { + textAlign: 'center', + marginTop: 20, + marginHorizontal: 30, + }, +})); diff --git a/frontend/app/screens/walkthroughs/walkthroughScreen.js b/frontend/app/screens/walkthroughs/walkthroughScreen.js new file mode 100644 index 0000000..f0c21b5 --- /dev/null +++ b/frontend/app/screens/walkthroughs/walkthroughScreen.js @@ -0,0 +1,61 @@ +import React from 'react'; +import { View } from 'react-native'; +import { RkStyleSheet } from 'react-native-ui-kitten'; +import { + GradientButton, + PaginationIndicator, +} from '../../components/'; +import { Walkthrough } from '../../components/walkthrough'; +import { Walkthrough1 } from './walkthrough1'; +import { Walkthrough2 } from './walkthrough2'; +import NavigationType from '../../config/navigation/propTypes'; + +export class WalkthroughScreen extends React.Component { + static propTypes = { + navigation: NavigationType.isRequired, + }; + static navigationOptions = { + header: null, + }; + + state = { + index: 0, + }; + + onWalkThroughIndexChanged = (index) => { + this.setState({ index }); + }; + + onStartButtonPressed = () => { + this.props.navigation.navigate('Articles2'); + }; + + render = () => ( + <View style={styles.screen}> + <Walkthrough onChanged={this.onWalkThroughIndexChanged}> + <Walkthrough1 /> + <Walkthrough2 /> + </Walkthrough> + <PaginationIndicator length={2} current={this.state.index} /> + <GradientButton + rkType='large' + style={styles.button} + text="GET STARTED" + onPress={this.onStartButtonPressed} + /> + </View> + ) +} + +const styles = RkStyleSheet.create(theme => ({ + screen: { + backgroundColor: theme.colors.screen.base, + paddingVertical: 28, + alignItems: 'center', + flex: 1, + }, + button: { + marginTop: 25, + marginHorizontal: 16, + }, +})); |