DEV Community

Nouran Samy
Nouran Samy

Posted on

Google Calendar Events with React

This article will cover the topic of viewing a full calendar in your React application and integrate with Google Calendar API to show events from your account.

First of all, we need a package that provides a full calendar UI. So we will Full Calendar Package. This package is very simple and has many features as localization, different views, theme customizations and more.

First steps would be to install the package in your react app and initialize an API_KEY and CLIENT_ID in your Google Console to use in Google Calendar APIs.

In your react component, Add the scopes needed by google calendar for user authorization and showing calendar events.

const SCOPES =
  "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/calendar.readonly https://www.googleapis.com/auth/calendar.events https://www.googleapis.com/auth/calendar";
Enter fullscreen mode Exit fullscreen mode

Multiple scopes can be added separated by spaces.

Second, you must add google Api script in your application on component mount like so

  const [events, setEvents] = useState(null);

  useEffect(() => {
    const script = document.createElement("script");
    script.async = true;
    script.defer = true;
    script.src = "https://apis.google.com/js/api.js";

    document.body.appendChild(script);

    script.addEventListener("load", () => {
      if (window.gapi) handleClientLoad();
    });
  }, []);
Enter fullscreen mode Exit fullscreen mode

This last part ensures that the authorization popup will show only when script is fully loaded and google api is ready.

The handleClientLoad() function loads the Auth2 library.

  const handleClientLoad = () => {
    window.gapi.load("client:auth2", initClient);
  };
Enter fullscreen mode Exit fullscreen mode

Th initClient() function will initialize the API client library and set up sign in state listeners.

const openSignInPopup = () => {
   window.gapi.auth2.authorize(
              { client_id: CLIENT_ID, scope: SCOPES },
              (res) => {
                if (res) {
                  if (res.access_token)
                    localStorage.setItem("access_token", res.access_token);

                  // Load calendar events after authentication
                  window.gapi.client.load("calendar", "v3", listUpcomingEvents);
                }
              }
            );
}  

const initClient = () => {
    if (!localStorage.getItem("access_token")) {
      openSignInPopup();
    } else {
      // Get events if access token is found without sign in popup
      fetch(
     `https://www.googleapis.com/calendar/v3/calendars/primary/events?key=${API_KEY}&orderBy=startTime&singleEvents=true`,
        {
          headers: {
            Authorization: `Bearer ${localStorage.getItem("access_token")}`,
          },
        }
      )
        .then((res) => {
          // Check if unauthorized status code is return open sign in popup
          if (res.status !== 401) {
            return res.json();
          } else {
            localStorage.removeItem("access_token");

            openSignInPopup();
          }
        })
        .then((data) => {
          if (data?.items) {
            setEvents(formatEvents(data.items));
          }
        });
    }
  };
Enter fullscreen mode Exit fullscreen mode

Here we are using two types of methods for fetching events, The first using the logged in gapi.client instance and the other using the access_token stored.

When using the gapi.client, we are calling a callback function listUpcomingEvents() to get the events of the user.

const listUpcomingEvents = () => {
    window.gapi.client.calendar.events
      .list({
        // Fetch events from user's primary calendar
        calendarId: "primary",
        showDeleted: true,
        singleEvents: true,
      })
      .then(function (response) {
        let events = response.result.items;

        if (events.length > 0) {
          setEvents(formatEvents(events));
        }
      });
  };
Enter fullscreen mode Exit fullscreen mode

Now that we have the events, we need to format them for Full calendar package event object structure.

const formatEvents = (list) => {
    return list.map((item) => ({
      title: item.summary,
      start: item.start.dateTime || item.start.date,
      end: item.end.dateTime || item.end.date,
    }));
  };
Enter fullscreen mode Exit fullscreen mode

We are only showing title, start date and end dates but there are more options in full calendar docs.

At last, we need to render the Full Calendar component

import FullCalendar from "@fullcalendar/react";
import dayGridPlugin from "@fullcalendar/daygrid";

return (
      <FullCalendar
        plugins={[dayGridPlugin]}
        initialView="dayGridMonth"
        events={events}
      />
  );
Enter fullscreen mode Exit fullscreen mode

Now we have a full calendar rendering google calendar events.

Hope this was a clear tutorial. Thank you and have a great day.

Top comments (5)

Collapse
 
naemtl profile image
M. Stinis

Hi! Thanks for the guide. I'm having issues connecting the FullCalendar component to Google's Calendar API. I followed this doc, but it seems to be outdated. fullcalendar.io/docs/google-calendar

When my component renders, I get the following error:
Error 401: invalid_client
The OAuth client was not found.

I think the problem is with my Client ID. Do you know what value from the Calendar Interface's settings I need to use? I've tried several, but I keep getting errors on render. Thanks!

Collapse
 
danielmugisha profile image
Daniel MUGISHA

what about creating an event?

Collapse
 
nouran96 profile image
Nouran Samy

This snippet is from the official docs of Google Calendar API

// Refer to the JavaScript quickstart on how to setup the environment:
// https://developers.google.com/calendar/quickstart/js
// Change the scope to 'https://www.googleapis.com/auth/calendar' and delete any
// stored credentials.

var event = {
  'summary': 'Google I/O 2015',
  'location': '800 Howard St., San Francisco, CA 94103',
  'description': 'A chance to hear more about Google\'s developer products.',
  'start': {
    'dateTime': '2015-05-28T09:00:00-07:00',
    'timeZone': 'America/Los_Angeles'
  },
  'end': {
    'dateTime': '2015-05-28T17:00:00-07:00',
    'timeZone': 'America/Los_Angeles'
  },
  'recurrence': [
    'RRULE:FREQ=DAILY;COUNT=2'
  ],
  'attendees': [
    {'email': 'lpage@example.com'},
    {'email': 'sbrin@example.com'}
  ],
  'reminders': {
    'useDefault': false,
    'overrides': [
      {'method': 'email', 'minutes': 24 * 60},
      {'method': 'popup', 'minutes': 10}
    ]
  }
};

var request = gapi.client.calendar.events.insert({
  'calendarId': 'primary',
  'resource': event
});

request.execute(function(event) {
  appendPre('Event created: ' + event.htmlLink);
});
Enter fullscreen mode Exit fullscreen mode

You can find more details about creating events from here
developers.google.com/calendar/api...

Collapse
 
joyfortheppl profile image
joyfortheppl

Hello Dev I have 3 questions.

  1. is all of this code supposed to be on one page ? (App.js)
  2. is all of this code supposed to be inside of the main react component and then return the full calendar function underneath it ?
  3. I'm a tech teacher in the states and this is the best walk thru I have seen. Thank you so much. Is there a github repository for this example ?

thanks.

Thread Thread
 
nouran96 profile image
Nouran Samy • Edited

Hello there,

1,2- All of this code is in the same component but it is just for demo purposes. Feel free to divide it into utils files for the main functions if you want.

3- Thank you so much. You can find the code in here
github.com/Nouran96/full-calendar-...