Adding appointment to calendar using Expo createEventAsync IOS

1.3k views Asked by At

SDK Version: 38 Platforms(Android/iOS):

I am having difficulties getting this code to return a calendar ID, I’d appreciate help from anyone as there seems to be very little information about the new calendar API change.

async obtainCalendarPermission() {
    let permission = await Permissions.getAsync(Permissions.CALENDAR)
     if (permission.status !== 'granted') {
       permission = await Permissions.askAsync(Permissions.CALENDAR)
       return
     }
    if (permission.status !== 'granted') {
      permission = await Permissions.askAsync(Permissions.REMINDERS)
      return
     
      if (permission.status !== 'granted') {
        Alert.alert('Permission not granted to calendar')
      }
    }
    return permission
  }

async function getDefaultCalendarSource() {
  const calendars = await Calendar.getCalendarsAsync()
  const defaultCalendars = calendars.filter(
    (each) => each.source.name === 'Default',
  )
  return defaultCalendars[0].source
}

async addReservationToCalendar(date){
    await this.obtainCalendarPermission()
    const permission = await Permissions.askAsync(Permissions.REMINDERS)
    if (permission.status !== 'granted') 
    var calendars = Calendar.getCalendarsAsync().then(calendars => console.log(calendars))
      
    const defaultCalendarSource = Platform.OS === 'ios' ? await getDefaultCalendarSource(): { isLocalAccount: true, name: 'Expo Calendar' };
  console.log(defaultCalendarSource ,+'emeka')

    let dateMs = Date.parse(date)
    let startDate = new Date(dateMs)
    let endDate = new Date(dateMs + 2 * 60 * 60 * 1000)

    const calendarId = await Calendar.createEventAsync(
      defaultCalendarSource.id,
      {
        title: 'Con Fusion Table Reservation',
        startDate: startDate,
        endDate: endDate,
        timeZone: 'Asia/Hong_Kong',
        location:
          '121, Clear Water Bay Road, Clear Water Bay, Kowloon, Hong Kong',
      },
    )}
2

There are 2 answers

0
emekaokoli On BEST ANSWER

I have solved it. I was having a hard time getting the calendar ID as it is a requirement for the new createEventAsync() API. this is the complete code that solved the problem for me, I am pasting it here so that someone can use or improve on it.

It generates a unique calendar ID and saves reservations to the calendar on IOS, I did not test it on android.

async function getDefaultCalendarSource() {
  await Calendar.getCalendarsAsync().then((id) => console.log(id))
}

 async obtainCalendarPermission() {
    let permission = await Permissions.getAsync(Permissions.CALENDAR)
    if (permission.status !== 'granted') {
      permission = await Permissions.askAsync(Permissions.CALENDAR)
      return
    }
    if (permission.status !== 'granted') {
      permission = await Permissions.askAsync(Permissions.REMINDERS)
      return

      if (permission.status !== 'granted') {
        Alert.alert('Permission not granted to calendar')
      }
    }
    return permission
  }
async addReservationToCalendar(date) {
    await this.obtainCalendarPermission()
    var dateMs = Date.parse(date)
    var startDate = new Date(dateMs)
    var endDate = new Date(dateMs + 2 * 60 * 60 * 1000)

    getDefaultCalendarSource()
    const newCalendar = await Calendar.createCalendarAsync({
      title: 'Test Reservation',
      color: '#512DA8',
      entityType: Calendar.EntityTypes.EVENT,
      sourceId: getDefaultCalendarSource.id,
      source: getDefaultCalendarSource,
      name: 'Restauran Reservation',
      ownerAccount: 'personal',
      accessLevel: Calendar.CalendarAccessLevel.OWNER,
    })

      .then((id) => {
        Calendar.createEventAsync(id, {
          title: 'Table Reservation',
          startDate: startDate,
          endDate: endDate,
          timeZone: 'Asia/Hong_Kong',
          location:
            '121, Clear Water Bay Road, Clear Water Bay, Kowloon, Hong Kong',
        }).catch((err) => console.log(err))
        // console.log(`calendar ID is: ${id}`)
      })
      .catch((err) => console.log(err))
  }
0
Antonio Mendiola On

In my case I decided to implement EVENTS for android and REMINDERS for iOS. I show you my solution, but it's a bit different. It works perfectly on both platforms.

I'm using:

  • "expo": "46.0.13"
  • "expo-calendar": "10.3.0"
  • "react-native": "0.69.6"
useEffect(() => {
        (async () => {
            if (Platform.OS === 'ios') {
            await requestTrackingPermissionsAsync(); 
            const remindersPermissions = await Calendar.requestRemindersPermissionsAsync(); 
            if(remindersPermissions.status !== 'granted')
                Alert.alert('Reminders access required', 'You must accept access to reminders in order to create reminders.', 
                [
                    { text: "Cancel", style: "cancel" },
                    { text: "OK", onPress: async () => await Calendar.requestRemindersPermissionsAsync() }
                ])
            }
            const calendarPermissions = await Calendar.requestCalendarPermissionsAsync(); 
            if(calendarPermissions.status === 'granted') {
              createCalendar()
            } else {
                Alert.alert('Access to calendars required', 'You must allow access to the calendar if you want to create reminders.', 
                [
                    { text: "Cancel", style: "cancel" },
                    { text: "OK", onPress: async () => await Calendar.requestCalendarPermissionsAsync() }
                ])
            }
        })();
    }, [])

const getDefaultCalendarSource = async() => {
        const defaultCalendar = await Calendar.getDefaultCalendarAsync();
        return defaultCalendar.source;
    }

const createCalendar = async () => {
        const calendarEntityType = Platform.OS === 'android' ? Calendar.EntityTypes.EVENT : Calendar.EntityTypes.REMINDER;
        const calendars = Platform.OS === 'android' ? await Calendar.getCalendarsAsync() : await Calendar.getCalendarsAsync(calendarEntityType);
        const existCalendar = calendars.find(calendar => calendar.title === DEFAULT_CALENDAR_NAME);
        if (!existCalendar) {
            const defaultCalendarSource = Platform.OS === 'ios' ? await getDefaultCalendarSource() : { isLocalAccount: true, name: DEFAULT_CALENDAR_NAME };    
            const newCalendarId = await Calendar.createCalendarAsync({
                title: DEFAULT_CALENDAR_NAME,
                name: DEFAULT_CALENDAR_NAME,
                color: primerColor,      
                entityType: calendarEntityType,
                accessLevel: Calendar.CalendarAccessLevel.OWNER,
                sourceId: defaultCalendarSource.id,
                source: defaultCalendarSource,
                ownerAccount: DEFAULT_CALENDAR_NAME,
            }); 
            globalContext.setCalendarId(newCalendarId)
        } else {
            const calendarIndex = calendars.findIndex(calendar => calendar.title === DEFAULT_CALENDAR_NAME);
            globalContext.setCalendarId(calendars[calendarIndex].id);
        }
    }

And to create Events/Reminders I have this function:

const onSetReminder = async (reminderDate) => {
    let reminderId;
    let eventId;
    
    Platform.OS === 'ios' && (async() => {
      reminderId = await Calendar.createReminderAsync(globalContext.calendarId, {
        title: `Reminder Title`,
        calendarId: globalContext.calendarId,
        startDate: reminderDate,
        dueDate: reminderDate,
        alarms: [{
          relativeOffset: -60,
          method: Calendar.AlarmMethod.ALERT
        }],
      });
    })();
    
    Platform.OS === 'android' && (async() => {
      eventId = await Calendar.createEventAsync(globalContext.calendarId, {
        title: `Event Title`,
        accessLevel: Calendar.EventAccessLevel.OWNER,
        calendarId: globalContext.calendarId,
        startDate: reminderDate,
        endDate: reminderDate,
        alarms: [{
          method: Calendar.AlarmMethod.ALERT,
          relativeOffset: -60,
        }],
      });
    })();
  };