eventlist: Section events by day

- Add pull to refresh
- Add infinite scroll
This commit is contained in:
nikolark committed 2017-07-23 02:20:06 +02:00
1 parent 77b173b7a6
commit 02c38ae6f2
3 files changed
+126 -46

No files matched your search

+62 -43
View File
@@ -1,41 +1,76 @@
import {Platform, StyleSheet, FlatList, Text, View, Linking, TouchableOpacity, ActivityIndicator} from "react-native";
import {StyleSheet, Linking, ActivityIndicator, View, SectionList} from "react-native";
import {Card, ListItem, CardItem, Body, Text as Text, Left, Right, Icon, Button, Content} from 'native-base';
import React, { Component } from 'react';
import moment from "moment";
import 'moment/locale/nb';
export default class EventList extends Component {
_keyExtractor = (item, index) => item.id;
_renderItem = ({item}) => (
<View>
<TouchableOpacity onPress={() => { this._onPressItem(item); }} style={[styles.listItem, styles.card]}>
<View>
<Text style={styles.listItemTitle}>{item.title.rendered}</Text>
<Text style={styles.listItemTime}>{this._formatTime(item.start_time)}</Text>
</View>
</TouchableOpacity>
</View>
<ListItem button onPress={() => { this._onPressItem(item); }} style={styles.listItem}>
<Body style={{flex: 5}}>
<Text style={styles.listItemTitle} numberOfLines={1}>{item.title.decoded}</Text>
<Text style={styles.listItemTime}>{this._formatTime(item.start_time)}</Text>
</Body>
<Right style={{flex: 1}}>
<Icon name="arrow-forward" />
</Right>
</ListItem>
);
_renderSectionHeader = ({section}) => {
return (<ListItem style={[styles.listItem, {paddingBottom: 8}]}>
<Body>
<Text style={styles.listItemSectionTitle}>{section.title}</Text>
</Body>
</ListItem>);
};
_renderFooter = () => {
if(!this.props.loading) {
return null;
}
return (<View style={{paddingVertical: 20}}>
<ActivityIndicator animating size="large" />
</View>);
};
_onPressItem = (item) => {
Linking.openURL(item.link);
};
_formatTime(time) {
moment.locale('nb');
return moment(time).format('llll');
}
render() {
if(this.props.loading) {
return (<View style={styles.card}><Text style={styles.loadingText}>Loading...</Text><ActivityIndicator/></View>)
if (this.props.error) {
return (<Content>
<Card style={{margin: 4}}>
<CardItem onPress={() => { this._onPressItem(item); }}>
<Text style={styles.loadingText}>Kunne ikke hente programmet...</Text>
</CardItem>
<CardItem>
<Button onPress={this.props.handleRefresh}><Text>Prøv igjen</Text></Button>
</CardItem>
</Card>
</Content>)
}
return (<FlatList
data={this.props.events}
return (<SectionList
sections={this.props.eventsSectioned}
renderItem={this._renderItem}
keyExtractor={this._keyExtractor}
style={styles.container}
renderSectionHeader={this._renderSectionHeader}
keyExtractor={(item) => item.id}
refreshing={this.props.refreshing}
onRefresh={this.props.handleRefresh}
onEndReached={this.props.handleLoadMore}
onEndReachedThreshould={10}
initialNumToRender={10}
ListFooterComponent={this._renderFooter}
style={styles.list}
/>);
}
}
@@ -43,40 +78,24 @@ export default class EventList extends Component {
const styles = StyleSheet.create({
listItem: {
height: 86,
marginLeft: 0
},
listItemTitle: {
fontSize: 16,
fontWeight: 'bold',
color: 'black'
fontSize: 14,
},
listItemTime: {
fontSize: 16,
color: 'black'
fontSize: 14,
color: '#666'
},
container: {
flex: 1,
},
card: {
borderColor: '#e1e8ee',
borderWidth: 1,
...Platform.select({
ios: {
shadowColor: 'rgba(0,0,0, .2)',
shadowOffset: { height: 0, width: 0 },
shadowOpacity: 1,
shadowRadius: 1,
},
android: {
elevation: 1,
},
}),
padding: 8,
margin: 8,
backgroundColor: '#fff',
listItemSectionTitle: {
fontSize: 14,
fontWeight: 'bold',
},
loadingText: {
textAlign: 'center',
paddingBottom: 8
},
list: {
backgroundColor: 'white'
}
});
+60 -3
View File
@@ -2,6 +2,8 @@ import {connect} from "react-redux";
import EventList from "./EventList";
import React from 'react';
import moment from "moment";
import 'moment/locale/nb';
/* Ref: https://medium.com/react-native-development/how-to-use-the-flatlist-component-react-native-basics-92c482816fe6 */
@@ -12,26 +14,81 @@ class EventListContainer extends React.Component {
this.state = {
loading: false,
events: [],
eventsSectioned: [],
page: 1,
noMorePages: false,
error: null,
refreshing: false,
};
}
_formatDate(time) {
moment.locale('nb');
return moment(time).format('ll');
}
_toSectionFormat(events) {
let sectioned = {};
events.map((event) => {
const title = this._formatDate(event.start_time);
if( title in sectioned ) {
sectioned[title].push(event);
} else {
sectioned[title] = [event];
}
});
let sectionedList = [];
Object.entries(sectioned).forEach(([title, section]) => {
sectionedList.push({data: section, title: title});
});
return sectionedList;
}
handleRefresh = () => {
this.setState({
page: 1,
refreshing: true,
noMorePages: false,
}, () => {
this.fetchEvents()
});
};
handleLoadMore = () => {
if(this.state.noMorePages || this.state.loading) {
return;
}
this.setState({
page: this.state.page + 1,
}, () => {
this.fetchEvents();
})
};
fetchEvents() {
const { page } = this.state;
const url = `https://studentersamfundet.no/wp-json/wp/v2/events?future=1`; //&page=${page}&results=20`;
const url = `https://studentersamfundet.no/wp-json/wp/v2/events?page=${page}&future=1`;
this.setState({ loading: true });
fetch(url)
.then(res => res.json())
.then(res => {
console.log(res);
if(res.code === 'rest_post_invalid_page_number') {
this.setState({
noMorePages: true
});
}
this.setState({
events: page === 1 ? res : [...this.state.events, ...res],
eventsSectioned: page === 1 ? this._toSectionFormat(res) : this._toSectionFormat([...this.state.events, ...res]),
error: res.error || null,
loading: false,
refreshing: false
});
})
.catch(error => {
this.setState({ error, loading: false });
@@ -43,7 +100,7 @@ class EventListContainer extends React.Component {
}
render() {
return (<EventList {...this.state} />)
return (<EventList {...{...this.state, handleRefresh: this.handleRefresh, handleLoadMore: this.handleLoadMore}} />)
}
}