1import React from 'react'; 2import { Alert, Platform, ScrollView, StyleSheet, Text, View } from 'react-native'; 3import { NavigationScreenProps } from 'react-navigation'; 4import * as Calendar from 'expo-calendar'; 5import Button from '../components/Button'; 6import HeadingText from '../components/HeadingText'; 7import ListButton from '../components/ListButton'; 8import MonoText from '../components/MonoText'; 9 10const EventRow: React.FunctionComponent<{ 11 event: Calendar.Event; 12 getEvent: (event: Calendar.Event) => void; 13 getAttendees: (event: Calendar.Event) => void; 14 updateEvent: (event: Calendar.Event) => void; 15 deleteEvent: (event: Calendar.Event) => void; 16 openEventInCalendar: (event: Calendar.Event) => void; 17}> = ({ 18 event, 19 getEvent, 20 getAttendees, 21 updateEvent, 22 deleteEvent, 23 openEventInCalendar, 24}) => ( 25 <View style={styles.eventRow}> 26 <HeadingText>{event.title}</HeadingText> 27 <MonoText>{JSON.stringify(event, null, 2)}</MonoText> 28 <ListButton onPress={() => getEvent(event)} title="Get Event Using ID" /> 29 <ListButton onPress={() => getAttendees(event)} title="Get Attendees for Event" /> 30 <ListButton onPress={() => updateEvent(event)} title="Update Event" /> 31 <ListButton onPress={() => deleteEvent(event)} title="Delete Event" /> 32 {Platform.OS === 'android' && ( 33 <ListButton 34 onPress={() => openEventInCalendar(event)} 35 title="Open in Calendar App" 36 /> 37 )} 38 </View> 39); 40 41interface State { 42 events: Calendar.Event[]; 43} 44 45export default class EventsScreen extends React.Component<NavigationScreenProps, State> { 46 static navigationOptions = { 47 title: 'Events', 48 }; 49 50 readonly state: State = { 51 events: [], 52 }; 53 54 componentDidMount() { 55 const { params } = this.props.navigation.state; 56 if (params) { 57 const { id } = params.calendar; 58 if (id) { 59 this._findEvents(id); 60 } 61 } 62 } 63 64 _findEvents = async (id: string) => { 65 const yesterday = new Date(); 66 yesterday.setDate(yesterday.getDate() - 1); 67 const nextYear = new Date(); 68 nextYear.setFullYear(nextYear.getFullYear() + 1); 69 const events = await Calendar.getEventsAsync([id], yesterday, nextYear); 70 this.setState({ events }); 71 } 72 73 _addEvent = async (recurring: boolean) => { 74 const { calendar } = this.props.navigation.state.params!; 75 if (!calendar.allowsModifications) { 76 Alert.alert('This calendar does not allow modifications'); 77 return; 78 } 79 const timeInOneHour = new Date(); 80 timeInOneHour.setHours(timeInOneHour.getHours() + 1); 81 const newEvent: { 82 title: string, 83 location: string, 84 startDate: Date, 85 endDate: Date, 86 notes: string, 87 timeZone: string, 88 recurrenceRule?: { 89 occurrence: number; 90 frequency: string; 91 } 92 } = { 93 title: 'Celebrate Expo', 94 location: '420 Florence St', 95 startDate: new Date(), 96 endDate: timeInOneHour, 97 notes: 'It\'s cool', 98 timeZone: 'America/Los_Angeles', 99 }; 100 if (recurring) { 101 newEvent.recurrenceRule = { 102 occurrence: 5, 103 frequency: 'daily', 104 }; 105 } 106 try { 107 await Calendar.createEventAsync(calendar.id, newEvent as any); 108 Alert.alert('Event saved successfully'); 109 this._findEvents(calendar.id); 110 } catch (e) { 111 Alert.alert('Event not saved successfully', e.message); 112 } 113 } 114 115 _getEvent = async (event: Calendar.Event) => { 116 try { 117 const newEvent = await Calendar.getEventAsync(event.id!, { 118 futureEvents: false, 119 instanceStartDate: event.startDate, 120 }); 121 Alert.alert('Event found using getEventAsync', JSON.stringify(newEvent)); 122 } catch (e) { 123 Alert.alert('Error finding event', e.message); 124 } 125 } 126 127 _getAttendees = async (event: Calendar.Event) => { 128 try { 129 const attendees = await Calendar.getAttendeesForEventAsync(event.id!, { 130 futureEvents: false, 131 instanceStartDate: event.startDate, 132 }); 133 Alert.alert('Attendees found using getAttendeesForEventAsync', JSON.stringify(attendees)); 134 } catch (e) { 135 Alert.alert('Error finding attendees', e.message); 136 } 137 } 138 139 _updateEvent = async (event: Calendar.Event) => { 140 const { calendar } = this.props.navigation.state.params!; 141 if (!calendar.allowsModifications) { 142 Alert.alert('This calendar does not allow modifications'); 143 return; 144 } 145 const newEvent = { 146 title: 'update test', 147 }; 148 try { 149 await Calendar.updateEventAsync(event.id!, newEvent, { 150 futureEvents: false, 151 instanceStartDate: event.startDate, 152 }); 153 Alert.alert('Event saved successfully'); 154 this._findEvents(calendar.id); 155 } catch (e) { 156 Alert.alert('Event not saved successfully', e.message); 157 } 158 } 159 160 _deleteEvent = async (event: Calendar.Event) => { 161 try { 162 const { calendar } = this.props.navigation.state.params!; 163 await Calendar.deleteEventAsync(event.id!, { 164 futureEvents: false, 165 instanceStartDate: event.recurrenceRule ? event.startDate : undefined, 166 }); 167 Alert.alert('Event deleted successfully'); 168 this._findEvents(calendar.id); 169 } catch (e) { 170 Alert.alert('Event not deleted successfully', e.message); 171 } 172 } 173 174 _openEventInCalendar = (event: Calendar.Event) => { 175 Calendar.openEventInCalendar(event.id!); 176 } 177 178 _renderActionButtons = () => { 179 return ( 180 <View> 181 <Button 182 onPress={() => this._addEvent(false)} 183 style={{ marginBottom: 10 }} 184 title="Add New Event" 185 /> 186 <Button onPress={() => this._addEvent(true)} title="Add New Recurring Event" /> 187 </View> 188 ); 189 } 190 191 render() { 192 const events = this.state.events.length ? ( 193 <View> 194 {this.state.events.map(event => ( 195 <EventRow 196 event={event} 197 key={`${event.id}${event.startDate}`} 198 getEvent={this._getEvent} 199 getAttendees={this._getAttendees} 200 updateEvent={this._updateEvent} 201 deleteEvent={this._deleteEvent} 202 openEventInCalendar={this._openEventInCalendar} 203 /> 204 ))} 205 </View> 206 ) : ( 207 <Text style={{ marginVertical: 12 }}>This calendar has no events.</Text> 208 ); 209 return ( 210 <ScrollView style={styles.container}> 211 {this._renderActionButtons()} 212 {events} 213 </ScrollView> 214 ); 215 } 216} 217 218const styles = StyleSheet.create({ 219 container: { 220 paddingHorizontal: 10, 221 paddingVertical: 16, 222 flex: 1, 223 }, 224 eventRow: { 225 marginBottom: 12, 226 }, 227}); 228