Skip to content

Commit

Permalink
2 - Desafio
Browse files Browse the repository at this point in the history
  • Loading branch information
douglaszaltron committed Jan 22, 2019
1 parent 61f40aa commit 3ca94aa
Show file tree
Hide file tree
Showing 28 changed files with 967 additions and 460 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"Reactotron",
"devtools",
"gonative",
"ionicons"
"ionicons",
"repos"
]
}
520 changes: 520 additions & 0 deletions android/app/src/main/assets/index.android.bundle

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 0 additions & 46 deletions src/components/Header/index.js

This file was deleted.

28 changes: 0 additions & 28 deletions src/components/Header/styles.js

This file was deleted.

32 changes: 6 additions & 26 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,9 @@
import './config/ReactotronConfig';
import './config/DevToolsConfig';
import React from 'react';
import '~/config/ReactotronConfig';
import '~/config/DevToolsConfig';

import React, { Component } from 'react';
import { AsyncStorage } from 'react-native';
import Routes from './routes';

import createNavigator from './routes';
const App = () => <Routes />;

export default class App extends Component {
state = {
userChecked: false,
userLogged: false,
};

async componentDidMount() {
const username = await AsyncStorage.getItem('@Githuber:username');
this.setState({ userChecked: true, userLogged: !!username });
}

render() {
const { userChecked, userLogged } = this.state;

if (!userChecked) return null;

const Routes = createNavigator(userLogged);

return <Routes />;
}
}
export default App;
37 changes: 37 additions & 0 deletions src/pages/Issues/IssueItem/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import PropTypes from 'prop-types';

import {
View, Text, Image, TouchableOpacity, Linking,
} from 'react-native';
import { withNavigation } from 'react-navigation';

import Icon from 'react-native-ionicons';

import styles from './styles';

const IssueItem = ({ issue }) => (
<TouchableOpacity style={styles.container} onPress={() => Linking.openURL(issue.html_url)}>
<Image style={styles.avatar} source={{ uri: issue.user.avatar_url }} />
<View style={styles.wrapper}>
<Text style={styles.title} numberOfLines={1} ellipsizeMode="tail">
{issue.title}
</Text>
<Text style={styles.subtitle}>{issue.user.login}</Text>
</View>
<Icon style={styles.icon} name="ios-arrow-forward" size={16} />
</TouchableOpacity>
);

IssueItem.propTypes = {
issue: PropTypes.shape({
title: PropTypes.string,
user: PropTypes.shape({
login: PropTypes.string,
avatar_url: PropTypes.string,
}),
html_url: PropTypes.string,
}).isRequired,
};

export default withNavigation(IssueItem);
39 changes: 39 additions & 0 deletions src/pages/Issues/IssueItem/styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { StyleSheet } from 'react-native';
import { colors, metrics } from '~/styles';

const styles = StyleSheet.create({
container: {
alignItems: 'center',
flexDirection: 'row',
backgroundColor: colors.white,
borderRadius: metrics.baseRadius,
padding: metrics.basePadding / 2,
marginHorizontal: metrics.baseMargin * 2,
marginBottom: metrics.baseMargin,
},
avatar: {
height: 40,
width: 40,
borderRadius: 20,
},
wrapper: {
flex: 1,
justifyContent: 'center',
paddingLeft: metrics.basePadding / 2,
paddingRight: metrics.basePadding / 2,
},
title: {
fontSize: 16,
fontWeight: 'bold',
color: colors.darker,
},
subtitle: {
fontSize: 14,
color: colors.regular,
},
icon: {
color: colors.light,
},
});

export default styles;
27 changes: 27 additions & 0 deletions src/pages/Issues/IssueSegmented/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import PropTypes from 'prop-types';

import { View, TouchableOpacity, Text } from 'react-native';

import styles from './styles';

const Filter = ({ segmented, onChangeSegmented }) => (
<View style={styles.container}>
<TouchableOpacity style={styles.wrapper} onPress={() => onChangeSegmented('all')}>
<Text style={[styles.title, segmented === 'all' && styles.active]}>Todas</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.wrapper} onPress={() => onChangeSegmented('open')}>
<Text style={[styles.title, segmented === 'open' && styles.active]}>Abertas</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.wrapper} onPress={() => onChangeSegmented('closed')}>
<Text style={[styles.title, segmented === 'closed' && styles.active]}>Fechadas</Text>
</TouchableOpacity>
</View>
);

Filter.propTypes = {
segmented: PropTypes.string.isRequired,
onChangeSegmented: PropTypes.func.isRequired,
};

export default Filter;
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import { StyleSheet } from 'react-native';

import { colors, metrics } from '~/styles';

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: colors.white,
borderRadius: metrics.baseRadius,
padding: metrics.basePadding,
backgroundColor: colors.light,
flexDirection: 'row',
marginHorizontal: metrics.baseMargin * 2,
marginTop: metrics.baseMargin,
alignItems: 'center',
maxWidth: (metrics.screenWidth - 40) / 2,
borderBottomColor: colors.lightTransparent,
borderBottomWidth: 1,
borderRadius: metrics.baseRadius,
},

avatar: {
width: 50,
height: 50,
wrapper: {
flex: 1,
alignItems: 'center',
padding: metrics.basePadding / 2,
borderRadius: metrics.baseRadius,
borderWidth: 1,
borderColor: colors.light,
},

title: {
color: colors.regular,
fontSize: 14,
fontWeight: 'bold',
},
active: {
color: colors.darker,
marginTop: metrics.baseMargin,
},
});

Expand Down
101 changes: 101 additions & 0 deletions src/pages/Issues/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React, { Component } from 'react';

import {
View, Text, ActivityIndicator, Alert, FlatList,
} from 'react-native';

import api from '~/services/api';
import IssueItem from './IssueItem';
import IssueSegmented from './IssueSegmented';
import styles from './styles';

export default class Issues extends Component {
static navigationOptions = ({ navigation }) => ({
title: navigation.getParam('title'),
});

state = {
items: [],
segmented: 'all',
loading: true,
refreshing: false,
};

componentDidMount() {
this.loadIssues();
}

loadIssues = async () => {
this.setState({ refreshing: true });

const { navigation } = this.props;
const { segmented } = this.state;

try {
const { data } = await api.get(
`/repos/${navigation.getParam('full_name')}/issues?state=${segmented}`,
);

this.setState({ items: data });
} catch (error) {
Alert.alert('Ops!', 'Erro ao recuperar as Issues');
} finally {
this.setState({ loading: false, refreshing: false });
}
};

onChangeSegmented = async (value) => {
this.setState({ segmented: value });
this.setState({ refreshing: true });

const { navigation } = this.props;

try {
const { data } = await api.get(
`/repos/${navigation.getParam('full_name')}/issues?state=${value}`,
);

this.setState({ items: data });
} catch (error) {
Alert.alert('Ops!', 'Erro ao recuperar as Issues');
} finally {
this.setState({ loading: false, refreshing: false });
}
};

renderListItem = ({ item }) => <IssueItem issue={item} />;

renderList = () => {
const { items, refreshing } = this.state;

if (!items.length) {
return <Text style={styles.empty}>Nenhuma issue encontrada</Text>;
}

return (
<FlatList
data={items}
keyExtractor={item => String(item.id)}
renderItem={this.renderListItem}
onRefresh={this.loadIssues}
refreshing={refreshing}
/>
);
};

render() {
const { loading, segmented } = this.state;

return (
<View style={styles.container}>
<IssueSegmented segmented={segmented} onChangeSegmented={this.onChangeSegmented} />
<View style={styles.divider} />
{loading ? (
<ActivityIndicator size="large" color={styles.loading.color} style={styles.loading} />
) : (
this.renderList()
)}
</View>
);
}
}
Loading

0 comments on commit 3ca94aa

Please sign in to comment.