Skip to content

Commit 33fc9e1

Browse files
Merge pull request #205 from StoDevX/revamp-calendar
Revamp the calendar view
2 parents d7ed569 + 9e7837d commit 33fc9e1

File tree

2 files changed

+131
-69
lines changed

2 files changed

+131
-69
lines changed

views/calendar/calendar.js

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@ import {
1111
Platform,
1212
ListView,
1313
RefreshControl,
14+
View,
1415
} from 'react-native'
1516

17+
import groupBy from 'lodash/groupBy'
18+
import moment from 'moment-timezone'
1619
import delay from 'delay'
1720
import LoadingView from '../components/loading'
1821
import qs from 'querystring'
1922
import EventView from './event'
23+
import * as c from '../components/colors'
2024
import { GOOGLE_CALENDAR_API_KEY } from '../../lib/config'
2125

2226
type GoogleCalendarTimeType = {
@@ -36,7 +40,8 @@ export default class CalendarView extends React.Component {
3640

3741
state = {
3842
events: new ListView.DataSource({
39-
rowHasChanged: this._rowHasChanged,
43+
rowHasChanged: this.rowHasChanged,
44+
sectionHeaderHasChanged: this.sectionHeaderHasChanged,
4045
}),
4146
loaded: false,
4247
refreshing: true,
@@ -47,8 +52,12 @@ export default class CalendarView extends React.Component {
4752
this.refresh()
4853
}
4954

50-
_rowHasChanged(r1: GoogleCalendarEventType, r2: GoogleCalendarEventType) {
51-
return r1.summary != r2.summary
55+
rowHasChanged(r1: GoogleCalendarEventType, r2: GoogleCalendarEventType) {
56+
return r1.summary !== r2.summary
57+
}
58+
59+
sectionHeaderHasChanged(h1: number, h2: number) {
60+
return h1 !== h2
5261
}
5362

5463
buildCalendarUrl(calendarId: string) {
@@ -79,7 +88,12 @@ export default class CalendarView extends React.Component {
7988
}
8089

8190
if (data) {
82-
this.setState({events: this.state.events.cloneWithRows(data)})
91+
data.forEach(event => {
92+
event.startTime = moment(event.start.date || event.start.dateTime)
93+
event.endTime = moment(event.end.date || event.end.dateTime)
94+
})
95+
let grouped = groupBy(data, event => event.startTime.format('ddd MMM Do'))
96+
this.setState({events: this.state.events.cloneWithRowsAndSections(grouped)})
8397
}
8498
if (error) {
8599
this.setState({error: error.message})
@@ -102,6 +116,32 @@ export default class CalendarView extends React.Component {
102116
this.setState({refreshing: false})
103117
}
104118

119+
renderRow = (data: Object) => {
120+
return (
121+
<EventView
122+
style={styles.row}
123+
eventTitle={data.summary}
124+
startTime={data.startTime}
125+
endTime={data.endTime}
126+
location={data.location}
127+
/>
128+
)
129+
}
130+
131+
renderSectionHeader = (sectionData: Object, sectionIdentifier: any) => {
132+
return (
133+
<View style={styles.rowSectionHeader}>
134+
<Text style={styles.rowSectionHeaderText} numberOfLines={1}>
135+
{sectionIdentifier}
136+
</Text>
137+
</View>
138+
)
139+
}
140+
141+
renderSeparator = (sectionID: any, rowID: any) => {
142+
return <View key={`${sectionID}-${rowID}`} style={styles.separator} />
143+
}
144+
105145
render() {
106146
if (!this.state.loaded) {
107147
return <LoadingView />
@@ -117,15 +157,9 @@ export default class CalendarView extends React.Component {
117157
contentInset={{bottom: Platform.OS === 'ios' ? 49 : 0}}
118158
dataSource={this.state.events}
119159
pageSize={5}
120-
renderRow={data =>
121-
<EventView
122-
style={styles.row}
123-
eventTitle={data.summary}
124-
startTime={data.start.dateTime}
125-
endTime={data.end.dateTime}
126-
location={data.location}
127-
/>
128-
}
160+
renderRow={this.renderRow}
161+
renderSectionHeader={this.renderSectionHeader}
162+
renderSeparator={this.renderSeparator}
129163
refreshControl={
130164
<RefreshControl
131165
refreshing={this.state.refreshing}
@@ -143,10 +177,24 @@ let styles = StyleSheet.create({
143177
backgroundColor: '#ffffff',
144178
},
145179
row: {
146-
minHeight: 88,
147-
marginLeft: 10,
148-
paddingRight: 10,
149-
borderBottomWidth: 1,
180+
// marginLeft: 10,
181+
// paddingRight: 10,
182+
},
183+
separator: {
184+
borderBottomWidth: StyleSheet.hairlineWidth,
150185
borderBottomColor: '#ebebeb',
151186
},
187+
rowSectionHeader: {
188+
backgroundColor: c.iosListSectionHeader,
189+
paddingTop: 5,
190+
paddingBottom: 5,
191+
paddingLeft: 10,
192+
borderTopWidth: 1,
193+
borderBottomWidth: 1,
194+
borderColor: '#ebebeb',
195+
},
196+
rowSectionHeaderText: {
197+
color: 'black',
198+
fontWeight: 'bold',
199+
},
152200
})

views/calendar/event.js

Lines changed: 66 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -5,80 +5,94 @@ import {
55
Text,
66
} from 'react-native'
77

8+
import moment from 'moment-timezone'
89
import * as c from '../components/colors'
9-
import padEnd from 'lodash/padEnd'
1010
import {getText, parseHtml} from '../../lib/html'
1111

1212
let styles = StyleSheet.create({
13-
itemTitle: {
14-
color: c.black,
13+
container: {
14+
paddingVertical: 2,
15+
// paddingLeft: 10,
16+
flexDirection: 'row',
17+
},
18+
rowIllusion: {
19+
paddingVertical: 4,
20+
},
21+
times: {
22+
width: 70,
23+
flexDirection: 'column',
24+
justifyContent: 'space-between',
25+
paddingRight: 12,
26+
paddingLeft: 4,
27+
},
28+
timeText: {
29+
textAlign: 'right',
30+
fontSize: 10,
31+
},
32+
startTime: {
33+
// marginTop: 3,
34+
color: 'black',
35+
},
36+
endTime: {
37+
color: c.iosText,
38+
},
39+
texts: {
1540
paddingLeft: 10,
16-
paddingRight: 10,
17-
paddingTop: 10,
41+
flex: 1,
42+
borderLeftWidth: 2,
43+
borderLeftColor: c.iosGray,
44+
},
45+
title: {
46+
color: c.black,
47+
fontWeight: '500',
1848
paddingBottom: 3,
19-
fontSize: 16,
20-
textAlign: 'left',
49+
fontSize: 14,
2150
},
22-
itemPreview: {
51+
location: {
2352
color: c.iosText,
24-
paddingLeft: 10,
25-
paddingRight: 10,
26-
paddingBottom: 6,
27-
fontSize: 13,
28-
textAlign: 'left',
53+
fontSize: 10,
2954
},
3055
})
3156

32-
function getString(date) {
33-
let month = date.getMonth() + 1 // offset since JS uses 0-11, not 1-12
34-
let day = date.getDate()
35-
36-
let hours = date.getHours()
37-
let isMorning = true
38-
if (date.getHours() > 12) {
39-
hours = date.getHours() - 12
40-
isMorning = false
41-
}
42-
43-
let min = date.getMinutes()
44-
if (min.toString().length < 2) {
45-
min = padEnd(min, 2, '0')
46-
}
47-
48-
if (isMorning) {
49-
min += 'AM'
50-
} else {
51-
min += 'PM'
52-
}
53-
54-
return `${month}/${day} ${hours}:${min}`
55-
}
56-
5757
// PROPS: eventTitle, location, startTime, endTime
58-
export default function EventView(props: {eventTitle: string, location: string, startTime?: string, endTime?: string, style?: any}) {
58+
export default function EventView(props: {eventTitle: string, location: string, startTime?: Object, endTime?: Object, style?: any}) {
5959
let title = getText(parseHtml(props.eventTitle))
6060

61-
let st = new Date(props.startTime)
62-
let et = new Date(props.endTime)
61+
let eventLength = moment.duration(props.endTime.diff(props.startTime)).asHours()
62+
let allDay = eventLength === 24
63+
let multiDay = eventLength > 24
6364

64-
let stString = getString(st)
65-
let etString = getString(et)
66-
67-
let showTimes = props.startTime && props.endTime
68-
let showLocation = Boolean(props.location)
65+
let times = null
66+
if (allDay) {
67+
times = <Text style={[styles.timeText, styles.startTime]}>all-day</Text>
68+
} else if (multiDay) {
69+
times = [
70+
<Text key={0} style={[styles.timeText, styles.startTime]}>{props.startTime.format('h:mma')}</Text>,
71+
<Text key={1} style={[styles.timeText, styles.endTime]}>to {props.endTime.format('MMM. D h:mma')}</Text>,
72+
]
73+
} else {
74+
times = [
75+
<Text key={0} style={[styles.timeText, styles.startTime]}>{props.startTime.format('h:mma')}</Text>,
76+
<Text key={1} style={[styles.timeText, styles.endTime]}>{props.endTime.format('h:mma')}</Text>,
77+
]
78+
}
6979

7080
return (
71-
<View style={props.style}>
72-
<Text style={styles.itemTitle}>{title}</Text>
73-
{ showTimes ? <Text style={styles.itemPreview}>{stString} - {etString}</Text> : null }
74-
{ showLocation ? <Text style={styles.itemPreview}>{props.location}</Text> : null }
81+
<View style={[styles.container, props.style]}>
82+
<View style={[styles.rowIllusion, styles.times]}>
83+
{times}
84+
</View>
85+
<View style={[styles.rowIllusion, styles.texts]}>
86+
<Text style={styles.title}>{title}</Text>
87+
<Text style={styles.location}>{props.location}</Text>
88+
</View>
7589
</View>
7690
)
7791
}
7892
EventView.propTypes = {
79-
endTime: React.PropTypes.string,
93+
endTime: React.PropTypes.object,
8094
eventTitle: React.PropTypes.string.isRequired,
8195
location: React.PropTypes.string,
82-
startTime: React.PropTypes.string,
96+
startTime: React.PropTypes.object,
8397
style: React.PropTypes.oneOfType([React.PropTypes.number, React.PropTypes.object]),
8498
}

0 commit comments

Comments
 (0)