React Calendar: A Guide to Building Dynamic Calendars with Events and Todos
Tags: react, webdev, tutorial, typescript
Published: 2023-08-28 13:48:51


#Table of Contents

- [Introduction](#introduction)
- [Key Features](#key-features)
- [Setting up the Project](#setting-up-the-Project)
- [Create the Calendar](#create-the-Calendar)
- [Modals](#modals)
  - [AddEventModal.tsx](#addeventmodal)
  - [EventInfoModal](#eventinfomodal)
  - [AddDatePickerEventModal](#adddatepickereventmodal)
  - [AddTodoModal](#addtodomodal)
- [EventInfo](#eventinfo)
- [Conclusion](#conclusion)

#Introduction

Links:

[Live demo](https://react-calendar-example.vercel.app/)

[Github repo](https://github.com/Mumma6/react-calendar-example)

This tutorial aims to guide you through the process of building a calendar application using React and Material UI. With features like dynamic event creation, todo integration, and event color-coding, the application serves as a practical example of how to implement complex functionalities in a React app. We will use a variety of libraries and dependencies to achieve this, including `Material UI` components, `React Big Calendar`, and the `date-fns` library for localized date formats.

You can easily add on to this by integrate a database or add more info to your events.

#Key Features

**Event Management**

- Enables users to add, view, and manage events on the calendar.
- Allows for both slot-based and date-based event creation.

**Todo List Integration**

- Demonstrates how to integrate a todo list with a calendar application.
- Features options for creating todos and associating them with events.

**Event Color-Coding**

- Shows how to dynamically color-code events based on associated todos or other criteria.

**React Big Calendar**

- Uses React Big Calendar library for main calendar functionalities.

**Locale Support**

- Includes localized date formatting through the date-fns library.

##Setting up the Project

In this section, we'll walk you through the initial setup for building the calendar application. This involves initializing a new Next.js project and installing the necessary dependencies.

To start, let's create a new React project. Open your terminal and run the following command:

```Typescript
npx create-react-app react-calendar --template typescript
```

This will create a new directory called react-calendar with all the files you need. To navigate into your new app and start it, run:

```Typescript
cd react-calendar
npm run start
```

Your React application should now be accessible at `http://localhost:3000/`

**Installing Dependencies**
To build our calendar application, several packages are required. These include:

- Material-UI components (`@mui/material` and `@mui/icons-material`) for the UI.
- Emotion (`@emotion/react` and `@emotion/styled`) for additional styling capabilities.
- Date-fns (`date-fns`) for date manipulations.
- React Big Calendar (`react-big-calendar`) for the main calendar functionalities.
- React Colorful (`react-colorful`) for a color picker.


Install these dependencies by running the following command in your terminal:

**MUI and Emotion**
```Typescript
npm install @mui/material@5.14.6 @mui/icons-material@5.14.6 @emotion/react@11.11.1 @emotion/styled@11.11.0
```

**Date manipulation, calendar functionality, and a color picker.**
```Typescript
npm install date-fns@2.30.0 react-big-calendar@1.8.2 react-colorful@5.6.1 @mui/x-date-pickers@5.0.12 @types/react-big-calendar
```

After installing these dependencies, your project will have all the required packages to proceed with development. In the following sections, we'll dive into creating the various features for our calendar application.

#Create the Calendar

we'll go step by step through creating a calendar in React using Typescript. The calendar will have features for creating events, and todos.

First, you'll need to create a file called `EventCalendar.tsx` in your src/components directory. This file will contain all the logic for your calendar application.

> **Note:** As we add the code in chunks, you might see some errors initially. Don't worry, these will go away as we add more code.

Your overall folder structure should look like this:

```Typescript
src/components

 AddDatePickerEventModal.tsx
 AddEventModal.tsx
 AddTodoModal.tsx
 EventCalendar.tsx
 EventInfo.tsx
 EventInfoModal.tsx
```

##Importing Dependencies

In your `EventCalendar.tsx` file, add the following code to import all necessary dependencies:

```Typescript
import { useState, MouseEvent } from "react"
import { Box, Button, ButtonGroup, Card, CardContent, CardHeader, Container, Divider } from "@mui/material"

import { Calendar, type Event, dateFnsLocalizer } from "react-big-calendar"

import format from "date-fns/format"
import parse from "date-fns/parse"
import startOfWeek from "date-fns/startOfWeek"
import getDay from "date-fns/getDay"
import enUS from "date-fns/locale/en-US"

import "react-big-calendar/lib/css/react-big-calendar.css"

import EventInfo from "./EventInfo"
import AddEventModal from "./AddEventModal"
import EventInfoModal from "./EventInfoModal"
import { AddTodoModal } from "./AddTodoModal"
import AddDatePickerEventModal from "./AddDatePickerEventModal"
```

Here, we're importing everything we'll need for our calendar, including React hooks, material-UI components, and functionalities from react-big-calendar.

##Initialize the Localizer

Next, we'll initialize the date-fns localizer to handle date formatting.

```Typescript
const locales = {
  "en-US": enUS,
}

const localizer = dateFnsLocalizer({
  format,
  parse,
  startOfWeek,
  getDay,
  locales,
})
```

This sets up date-fns to work with react-big-calendar.

##Defining Data Models

We define our data models and utility functions like `generateId` to uniquely identify each todo and event. 

```Typescript
export interface ITodo {
  _id: string
  title: string
  color?: string
}

export interface IEventInfo extends Event {
  _id: string
  description: string
  todoId?: string
}

export interface EventFormData {
  description: string
  todoId?: string
}

export interface DatePickerEventFormData {
  description: string
  todoId?: string
  allDay: boolean
  start?: Date
  end?: Date
}

export const generateId = () => (Math.floor(Math.random() * 10000) + 1).toString()
```
Here, we define different interfaces for Events and Todos, along with some utility types.

##Initialize Form Data

// Make this better
We can add events in 2 different ways, the first is that we click and drag in the calender and the other is what we use a datePicker. Lets create the initial formData for both options

```Typescript
const initialEventFormState: EventFormData = {
  description: "",
  todoId: undefined,
}

const initialDatePickerEventFormData: DatePickerEventFormData = {
  description: "",
  todoId: undefined,
  allDay: false,
  start: undefined,
  end: undefined,
}
```

##Managing States

Next, let's declare all the state variables we'll be using:

```Typescript
const [openSlot, setOpenSlot] = useState(false)
  const [openDatepickerModal, setOpenDatepickerModal] = useState(false)
  const [openTodoModal, setOpenTodoModal] = useState(false)
  const [currentEvent, setCurrentEvent] = useState<Event | IEventInfo | null>(null)

  const [eventInfoModal, setEventInfoModal] = useState(false)

  const [events, setEvents] = useState<IEventInfo[]>([])
  const [todos, setTodos] = useState<ITodo[]>([])

  const [eventFormData, setEventFormData] = useState<EventFormData>(initialEventFormState)

  const [datePickerEventFormData, setDatePickerEventFormData] =
    useState<DatePickerEventFormData>(initialDatePickerEventFormData)
```

These states help us control modals, hold the current events, and keep track of todos.

Next up we can add our handlerFunctions, 

##Handling Events and Modals

We define several handler functions for handling slots, closing modals, and more.

```Typescript
 const handleSelectSlot = (event: Event) => {
    setOpenSlot(true)
    setCurrentEvent(event)
  }

  const handleSelectEvent = (event: IEventInfo) => {
    setCurrentEvent(event)
    setEventInfoModal(true)
  }

  const handleClose = () => {
    setEventFormData(initialEventFormState)
    setOpenSlot(false)
  }

  const handleDatePickerClose = () => {
    setDatePickerEventFormData(initialDatePickerEventFormData)
    setOpenDatepickerModal(false)
  }
```

These functions are called when certain actions are taken in our application, like selecting an event or a time slot in the calendar.

##Creating Events

Here is the core logic for adding new events to our calendar:

```Typescript
const onAddEvent = (e: MouseEvent<HTMLButtonElement>) => {
    e.preventDefault()

    const data: IEventInfo = {
      ...eventFormData,
      _id: generateId(),
      start: currentEvent?.start,
      end: currentEvent?.end,
    }

    const newEvents = [...events, data]

    setEvents(newEvents)
    handleClose()
  }

  const onAddEventFromDatePicker = (e: MouseEvent<HTMLButtonElement>) => {
    e.preventDefault()

    const addHours = (date: Date | undefined, hours: number) => {
      return date ? date.setHours(date.getHours() + hours) : undefined
    }

    const setMinToZero = (date: any) => {
      date.setSeconds(0)

      return date
    }

    const data: IEventInfo = {
      ...datePickerEventFormData,
      _id: generateId(),
      start: setMinToZero(datePickerEventFormData.start),
      end: datePickerEventFormData.allDay
        ? addHours(datePickerEventFormData.start, 12)
        : setMinToZero(datePickerEventFormData.end),
    }

    const newEvents = [...events, data]

    setEvents(newEvents)
    setDatePickerEventFormData(initialDatePickerEventFormData)
  }

  const onDeleteEvent = () => {
    setEvents(() => [...events].filter((e) => e._id !== (currentEvent as IEventInfo)._id!))
    setEventInfoModal(false)
  }
```

These functions add and delete events to our state, whether they're created by dragging on the calendar or via the date picker.


##Putting It All Together

Finally, we render our UI components and tie everything together:

```Typescript
return (
    <Box
      mt={2}
      mb={2}
      component="main"
      sx={{
        flexGrow: 1,
        py: 8,
      }}
    >
      <Container maxWidth={false}>
        <Card>
          <CardHeader title="Calendar" subheader="Create Events and Todos and manage them easily" />
          <Divider />
          <CardContent>
            <Box sx={{ display: "flex", justifyContent: "space-between" }}>
              <ButtonGroup size="large" variant="contained" aria-label="outlined primary button group">
                <Button onClick={() => setOpenDatepickerModal(true)} size="small" variant="contained">
                  Add event
                </Button>
                <Button onClick={() => setOpenTodoModal(true)} size="small" variant="contained">
                  Create todo
                </Button>
              </ButtonGroup>
            </Box>
            <Divider style={{ margin: 10 }} />
            <AddEventModal
              open={openSlot}
              handleClose={handleClose}
              eventFormData={eventFormData}
              setEventFormData={setEventFormData}
              onAddEvent={onAddEvent}
              todos={todos}
            />
            <AddDatePickerEventModal
              open={openDatepickerModal}
              handleClose={handleDatePickerClose}
              datePickerEventFormData={datePickerEventFormData}
              setDatePickerEventFormData={setDatePickerEventFormData}
              onAddEvent={onAddEventFromDatePicker}
              todos={todos}
            />
            <EventInfoModal
              open={eventInfoModal}
              handleClose={() => setEventInfoModal(false)}
              onDeleteEvent={onDeleteEvent}
              currentEvent={currentEvent as IEventInfo}
            />
            <AddTodoModal
              open={openTodoModal}
              handleClose={() => setOpenTodoModal(false)}
              todos={todos}
              setTodos={setTodos}
            />
            <Calendar
              localizer={localizer}
              events={events}
              onSelectEvent={handleSelectEvent}
              onSelectSlot={handleSelectSlot}
              selectable
              startAccessor="start"
              components={{ event: EventInfo }}
              endAccessor="end"
              defaultView="week"
              eventPropGetter={(event) => {
                const hasTodo = todos.find((todo) => todo._id === event.todoId)
                return {
                  style: {
                    backgroundColor: hasTodo ? hasTodo.color : "#b64fc8",
                    borderColor: hasTodo ? hasTodo.color : "#b64fc8",
                  },
                }
              }}
              style={{
                height: 900,
              }}
            />
          </CardContent>
        </Card>
      </Container>
    </Box>
  )
```

##Modals

**Creating Different Modals for Events and Todos**
Let's dive into the various modals that allow us to add new events and todos within our calendar application.

- **EventInfoModal:** This modal serves as an information panel that displays details about selected events. It provides users with a quick glance at the event description and offers an option to delete the event if necessary.
- **AddDatePickerEventModal:** This modal is specifically designed for adding new events to the calendar. It comes equipped with date and time pickers for specifying the event's start and end times and also allows the user to mark the event as an all-day event. A related todo can also be associated with the event for better task management.
- **AddEventModal:** This modal allows users to create new events with essential information such as event description, time, and date. It acts as a simplified version of AddDatePickerEventModal, designed for quick event creation.
- **AddTodoModal:** Beyond events, the application also supports the addition of 'todos'. This modal allows users to create new todos, complete with a title and a color code for easy identification. Users can also delete existing todos from within this modal.

###AddEventModal.tsx

We start with `AddEventModal.tsx`. This modal gets triggered when you click and drag on a specific time range in the calendar UI. Place this file in the same folder (`src/components`) where you have `EventCalendar.tsx`.

**Importing Dependencies**

First, we import various modules that we will be using, such as the Material UI components and the custom types for our application.

```Typescript
import { ChangeEvent, Dispatch, MouseEvent, SetStateAction } from "react"
import {
  TextField,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
  Button,
  Autocomplete,
  Box,
} from "@mui/material"
import { EventFormData, ITodo } from "./EventCalendar"
```

**Component Props**

We define the properties that this modal component expects using TypeScript's interface system. These props include booleans to control the modal's open state, functions to handle changes, and an array of Todo items.

```Typescript
interface IProps {
  open: boolean
  handleClose: Dispatch<SetStateAction<void>>
  eventFormData: EventFormData
  setEventFormData: Dispatch<SetStateAction<EventFormData>>
  onAddEvent: (e: MouseEvent<HTMLButtonElement>) => void
  todos: ITodo[]
}
```

**Component Functionality**

Within the functional component, we define the actual behavior of the modal:

- **onClose:** A function that calls the `handleClose` prop to close the modal.
- **onChange:** A function that handles changes in the text fields, updating the `eventFormData` state.
- **handleTodoChange:** A function that handles the selection of Todo items from the dropdown and updates the `eventFormData`.

The main return block of the component uses Material-UI components to render the modal's UI. It includes text fields for the event description and an autocomplete dropdown for Todo selection.

```Typescript
const AddEventModal = ({ open, handleClose, eventFormData, setEventFormData, onAddEvent, todos }: IProps) => {
  const { description } = eventFormData

  const onClose = () => handleClose()

  const onChange = (event: ChangeEvent<HTMLInputElement>) => {
    setEventFormData((prevState) => ({
      ...prevState,
      [event.target.name]: event.target.value,
    }))
  }

  const handleTodoChange = (e: React.SyntheticEvent, value: ITodo | null) => {
    setEventFormData((prevState) => ({
      ...prevState,
      todoId: value?._id,
    }))
  }

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogTitle>Add event</DialogTitle>
      <DialogContent>
        <DialogContentText>To add a event, please fill in the information below.</DialogContentText>
        <Box component="form">
          <TextField
            name="description"
            value={description}
            margin="dense"
            id="description"
            label="Description"
            type="text"
            fullWidth
            variant="outlined"
            onChange={onChange}
          />
          <Autocomplete
            onChange={handleTodoChange}
            disablePortal
            id="combo-box-demo"
            options={todos}
            sx={{ marginTop: 4 }}
            getOptionLabel={(option) => option.title}
            renderInput={(params) => <TextField {...params} label="Todo" />}
          />
        </Box>
      </DialogContent>
      <DialogActions>
        <Button color="error" onClick={onClose}>
          Cancel
        </Button>
        <Button disabled={description === ""} color="success" onClick={onAddEvent}>
          Add
        </Button>
      </DialogActions>
    </Dialog>
  )
}

export default AddEventModal
```

###EventInfoModal

The `EventInfoModal.tsx` component serves as an informational pop-up that appears when a user clicks on an existing event within the calendar. This modal allows users to view the details of the selected event and provides an option to delete it. Like the `AddEventModal.tsx`, this file should also be placed in the src/components folder.

At the beginning of the file, you'll find a series of imports for React, Material UI components, and custom types.

The IProps interface defines the properties that this component expects. It includes a boolean flag to indicate whether the modal is open or not, a handleClose function to close the modal, a onDeleteEvent function to delete the current event, and the data for the current event.

```Typescript
import { SetStateAction, MouseEvent, Dispatch } from "react"
import { Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, Button, Box, Typography } from "@mui/material"
import { IEventInfo } from "./EventCalendar"

interface IProps {
  open: boolean
  handleClose: Dispatch<SetStateAction<void>>
  onDeleteEvent: (e: MouseEvent<HTMLButtonElement>) => void
  currentEvent: IEventInfo | null
}

const EventInfoModal = ({ open, handleClose, onDeleteEvent, currentEvent }: IProps) => {
  const onClose = () => {
    handleClose()
  }

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogTitle>Event Info</DialogTitle>
      <DialogContent>
        <DialogContentText>
          <Typography sx={{ fontSize: 14, marginTop: 3 }} color="text.secondary" gutterBottom>
            {currentEvent?.description}
          </Typography>
        </DialogContentText>
        <Box component="form"></Box>
      </DialogContent>
      <DialogActions>
        <Button color="error" onClick={onClose}>
          Cancel
        </Button>
        <Button color="info" onClick={onDeleteEvent}>
          Delete Event
        </Button>
      </DialogActions>
    </Dialog>
  )
}

export default EventInfoModal
```

And that concludes our `EventInfoModal.tsx`. This component serves as a crucial piece in providing a user-friendly calendar application by allowing users to quickly view and manage their events.

###AddDatePickerEventModal

The `AddDatePickerEventModal.tsx` component is a specialized modal for adding events with date and time selections. This modal comes into play when you want to add an event that requires precise start and end times. It also features a checkbox to indicate if the event spans the entire day. Like the other modal components, place this file in the `src/components` directory.

**Importing Dependencies**

The top part of the file imports required modules from React, Material UI, and your custom types.

```Typescript
import React, { Dispatch, MouseEvent, SetStateAction, ChangeEvent } from "react"
import {
  TextField,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
  Button,
  Autocomplete,
  Box,
  Checkbox,
  Typography,
} from "@mui/material"
import { LocalizationProvider, DateTimePicker } from "@mui/x-date-pickers"
import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"
import { DatePickerEventFormData, ITodo } from "./EventCalendar"
```

**Component Props**

We define the expected properties in the `IProps` interface. These props include:

- **open:** Boolean flag indicating if the modal is open.
- **handleClose:** Function to close the modal.
- datePickerEventFormData: Object containing form data for the event.
- **setDatePickerEventFormData:** Function to update the form data.
- **onAddEvent:** Function to add a new event.
- **todos:** Array of Todo items.

```Typescript
interface IProps {
  open: boolean
  handleClose: Dispatch<SetStateAction<void>>
  datePickerEventFormData: DatePickerEventFormData
  setDatePickerEventFormData: Dispatch<SetStateAction<DatePickerEventFormData>>
  onAddEvent: (e: MouseEvent<HTMLButtonElement>) => void
  todos: ITodo[]
}
```

**Component Functionality**

Within `AddDatePickerEventModal`, several key functions are defined:

- **onClose:** Closes the modal by calling handleClose.
- **onChange:** Handles text input changes and updates the form data.
- **handleCheckboxChange:** Updates the allDay flag in the form data.
- **handleTodoChange:** Handles the Todo selection.
- **isDisabled:** Function to check if the "Add" button should be disabled based on the form data.

The main rendering block uses Material-UI components to render the UI, including date and time pickers.

```Typescript
const AddDatePickerEventModal = ({
  open,
  handleClose,
  datePickerEventFormData,
  setDatePickerEventFormData,
  onAddEvent,
  todos,
}: IProps) => {
  const { description, start, end, allDay } = datePickerEventFormData

  const onClose = () => {
    handleClose()
  }

  const onChange = (event: ChangeEvent<HTMLInputElement>) => {
    setDatePickerEventFormData((prevState) => ({
      ...prevState,
      [event.target.name]: event.target.value,
    }))
  }

  const handleCheckboxChange = (event: ChangeEvent<HTMLInputElement>) => {
    setDatePickerEventFormData((prevState) => ({
      ...prevState,
      allDay: event.target.checked,
    }))
  }

  const handleTodoChange = (e: React.SyntheticEvent, value: ITodo | null) => {
    setDatePickerEventFormData((prevState) => ({
      ...prevState,
      todoId: value?._id,
    }))
  }

  const isDisabled = () => {
    const checkend = () => {
      if (!allDay && end === null) {
        return true
      }
    }
    if (description === "" || start === null || checkend()) {
      return true
    }
    return false
  }

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogTitle>Add event</DialogTitle>
      <DialogContent>
        <DialogContentText>To add a event, please fill in the information below.</DialogContentText>
        <Box component="form">
          <TextField
            name="description"
            value={description}
            margin="dense"
            id="description"
            label="Description"
            type="text"
            fullWidth
            variant="outlined"
            onChange={onChange}
          />
          <LocalizationProvider dateAdapter={AdapterDateFns}>
            <Box mb={2} mt={5}>
              <DateTimePicker
                label="Start date"
                value={start}
                ampm={true}
                minutesStep={30}
                onChange={(newValue) =>
                  setDatePickerEventFormData((prevState) => ({
                    ...prevState,
                    start: new Date(newValue!),
                  }))
                }
                renderInput={(params) => <TextField {...params} />}
              />
            </Box>

            <Box>
              <Typography variant="caption" color="text" component={"span"}>
                All day?
              </Typography>
              <Checkbox onChange={handleCheckboxChange} value={allDay} />
            </Box>

            <DateTimePicker
              label="End date"
              disabled={allDay}
              minDate={start}
              minutesStep={30}
              ampm={true}
              value={allDay ? null : end}
              onChange={(newValue) =>
                setDatePickerEventFormData((prevState) => ({
                  ...prevState,
                  end: new Date(newValue!),
                }))
              }
              renderInput={(params) => <TextField {...params} />}
            />
          </LocalizationProvider>
          <Autocomplete
            onChange={handleTodoChange}
            disablePortal
            id="combo-box-demo"
            options={todos}
            sx={{ marginTop: 4 }}
            getOptionLabel={(option) => option.title}
            renderInput={(params) => <TextField {...params} label="Todo" />}
          />
        </Box>
      </DialogContent>
      <DialogActions>
        <Button color="error" onClick={onClose}>
          Cancel
        </Button>
        <Button disabled={isDisabled()} color="success" onClick={onAddEvent}>
          Add
        </Button>
      </DialogActions>
    </Dialog>
  )
}

export default AddDatePickerEventModal
```

`AddDatePickerEventModal.tsx` is an essential component that brings enhanced functionality to the calendar application. It provides a way to input more detailed events with start and end times or mark them as all-day events.

###AddTodoModal

`AddTodoModal.tsx` is another crucial component in your calendar application, serving as the interface for users to add new "Todo" items. It integrates various UI components and logic to facilitate adding new Todos, deleting existing ones, and customizing the color of each Todo.

**Importing Dependencies**

The component imports a mixture of built-in React hooks, Material UI components, and your custom types to build its functionality:

```Typescript
import { useState, Dispatch, SetStateAction } from "react"
import {
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
  Box,
  Button,
  Divider,
  IconButton,
  List,
  ListItem,
  ListItemText,
  TextField,
} from "@mui/material"
import DeleteIcon from "@mui/icons-material/Delete"

import { HexColorPicker } from "react-colorful"
import { ITodo, generateId } from "./EventCalendar"
```

**Component Props**
The props for this modal include:

- **open:** Boolean flag to control the visibility of the modal.
- **handleClose:** Function to close the modal.
- **todos:** Array of existing Todos.
- **setTodos:** Function to set the new list of Todos.

```Typescript
interface IProps {
  open: boolean
  handleClose: Dispatch<SetStateAction<void>>
  todos: ITodo[]
  setTodos: Dispatch<SetStateAction<ITodo[]>>
}
```

**Rendering and Layout**

The component leverages Material UI components for layout and styling. Notable features include:

- A color picker (HexColorPicker) for choosing the color of a Todo.
- A TextField for entering the title of the Todo.
- A List of existing Todos with delete buttons.
- Cancel and Add buttons in the Dialog actions.

**Event Handling**

Event handlers are attached to the form field for updating the title (`setTitle`) and the color picker (`setColor`), along with click handlers for adding (`onAddTodo`) and deleting (`onDeleteTodo`) Todos. The Add button is disabled if either the title or color is empty.

```Typescript
export const AddTodoModal = ({ open, handleClose, todos, setTodos }: IProps) => {
  const [color, setColor] = useState("#b32aa9")
  const [title, setTitle] = useState("")

  const onAddTodo = () => {
    setTitle("")
    setTodos([
      ...todos,
      {
        _id: generateId(),
        color,
        title,
      },
    ])
  }

  const onDeletetodo = (_id: string) => setTodos(todos.filter((todo) => todo._id !== _id))

  const onClose = () => handleClose()

  return (
    <Dialog open={open} onClose={onClose}>
      <DialogTitle>Add todo</DialogTitle>
      <DialogContent>
        <DialogContentText>Create todos to add to your Calendar.</DialogContentText>
        <Box>
          <TextField
            name="title"
            autoFocus
            margin="dense"
            id="title"
            label="Title"
            type="text"
            fullWidth
            sx={{ mb: 6 }}
            required
            variant="outlined"
            onChange={(e) => {
              setTitle(e.target.value)
            }}
            value={title}
          />
          <Box sx={{ display: "flex", justifyContent: "space-around" }}>
            <HexColorPicker color={color} onChange={setColor} />
            <Box sx={{ height: 80, width: 80, borderRadius: 1 }} className="value" style={{ backgroundColor: color }}></Box>
          </Box>
          <Box>
            <List sx={{ marginTop: 3 }}>
              {todos.map((todo) => (
                <ListItem
                  key={todo.title}
                  secondaryAction={
                    <IconButton onClick={() => onDeletetodo(todo._id)} color="error" edge="end">
                      <DeleteIcon />
                    </IconButton>
                  }
                >
                  <Box
                    sx={{ height: 40, width: 40, borderRadius: 1, marginRight: 1 }}
                    className="value"
                    style={{ backgroundColor: todo.color }}
                  ></Box>
                  <ListItemText primary={todo.title} />
                </ListItem>
              ))}
            </List>
          </Box>
        </Box>
      </DialogContent>
      <Divider />
      <DialogActions sx={{ marginTop: 2 }}>
        <Button sx={{ marginRight: 2 }} variant="contained" color="error" onClick={onClose}>
          Cancel
        </Button>
        <Button
          onClick={() => onAddTodo()}
          disabled={title === "" || color === ""}
          sx={{ marginRight: 2 }}
          variant="contained"
          color="success"
        >
          Add
        </Button>
      </DialogActions>
    </Dialog>
  )
}

```

##EventInfo

`EventInfo.tsx` is a straightforward yet essential component within your calendar application. It displays information about individual events. Right now we only show the description but you could add more things if you like.

```Typescript
import { Typography } from "@mui/material"
import { IEventInfo } from "./EventCalendar"

interface IProps {
  event: IEventInfo
}

const EventInfo = ({ event }: IProps) => {
  return (
    <>
      <Typography>{event.description}</Typography>
    </>
  )
}

export default EventInfo
```

#Conclusion

Congratulations! You've successfully built a dynamic calendar application using React, Material UI, and Typescript. We started from scratch, setting up our project environment and installing the necessary dependencies. Then, we dived into the core functionalities, covering everything from event management and todo integration to color coding and localization.

The application you've built is robust and feature-rich, thanks to the various libraries and components we've employed. You now have the skills to:

- Create and manage events on a calendar.
- Integrate a todo list within a calendar application.
- Color-code events based on associated todos or other criteria.
- Utilize the React Big Calendar library for additional functionalities.
- Apply localized date formats with the date-fns library.

Not only does this application serve as a practical tool, but it's also a great foundation for any future projects requiring calendar or scheduling functionalities. Feel free to expand upon this by adding more features or tweaking the existing ones to better suit your needs.

Thank you for following along, and happy coding!