Open In App

Event Management Web App using MERN

Last Updated : 04 Jan, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In this guide, we’ll walk through the step-by-step process of building a feature-rich Event Management Web App. We will make use of the MERN stack to build this project.

Preview of final output: Let us have a look at how the final output will look like.

Screenshot-2566-12-29-at-152922

Final Output of Event Management App

Prerequisite:

Approach to create Event Management Application:

  • Define the structure of an event using Mongoose schemas in a model file (e.g., `Event.js`).
  • Develop routes for handling Create, Read, Update, and Delete (CRUD) operations in a dedicated `eventRoutes.js` file.
  • Set up a MongoDB database and establish a connection in your Express application.
  • Create a server file (e.g., `server.js`) where Express is configured to listen on a specific port.
  • Design and implement a form component (`EventForm.js`) for adding new events.
  • Develop a component (`EventList.js`) to display a list of events fetched from the server.
  • Create a detailed event display component (`EventItem.js`) with features like editing, toggling reminders, and deleting.
  • Style your components for an engaging user interface. You can utilize CSS .

Steps to Setup Backend with Node.js and Express:

Step 1: Creating express app:

npm init -y

Step 2: Installing the required packages

npm install express mongoose body-parser cors

Project Structure:

Screenshot-2566-12-29-at-155011

Backend Project Structure

The updated dependencies in package.json file for backend will look like:

"dependencies": {
"body-parser": "^1.20.2",
"cors": "^2.8.5",
"express": "^4.18.2",
"mongoose": "^8.0.0",
}

Example: Below is the code example of the backend.

Javascript




// server.js
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cors = require('cors');
const eventRoutes = require('./routes/eventRoutes');
 
const app = express();
const PORT = process.env.PORT || 5000;
 
// Middleware
app.use(cors());
app.use(bodyParser.json());
 
// Connect to MongoDB
    useNewUrlParser: true,
    useUnifiedTopology: true,
}).then(() => {
    console.log('Connected to MongoDB')
});
 
// Routes
app.use('/api/events', eventRoutes);
 
// Start server
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});


Javascript




// routes/eventRoutes.js
const express = require('express');
const router = express.Router();
const Event = require('../models/Event');
 
// Get all events
router.get('/', async (req, res) => {
    try {
        const events = await Event.find();
        res.json(events);
    } catch (error) {
        res.status(500).json({ message: error.message });
    }
});
// Create a new event
router.post('/', async (req, res) => {
    const event = new Event({
        title: req.body.title,
        date: req.body.date,
        reminder: req.body.reminder || false,
    });
    try {
        const newEvent = await event.save();
        res.status(201).json(newEvent);
    } catch (error) {
        res.status(400).json({ message: error.message });
    }
});
 
// Delete an event
router.delete('/:id', async (req, res) => {
    console.log('****** Deleting event ******');
    try {
        console.log('Delete route called');
        // Use findByIdAndDelete instead of findByIdAndRemove
        await Event.findByIdAndDelete(req.params.id);
        console.log('Event deleted');
        res.json({ message: 'Event deleted' });
    } catch (error) {
        console.error('Error deleting event:', error);
        res.status(500).json({ message: error.message });
    }
});
// Update an event by ID
router.put('/:id', async (req, res) => {
    const eventId = req.params.id;
    const { title, date, reminder } = req.body;
 
    console.log('reminder', reminder);
    try {
        // Find the event by ID in the database
        const event = await Event.findById(eventId);
        if (!event) {
            return res.status(404).json({ message: 'Event not found' });
        }
 
        // Update the event properties
        event.date = date;
        event.title = title;
        event.reminder = reminder;
        console.log('event updated', event.reminder);
        // Save the updated event
        await event.save();
 
        // You can send the updated event in the response if needed
        res.json(event);
    } catch (error) {
        console.error('Error updating event:', error);
        res.status(500).json({ message: 'Internal Server Error' });
    }
});
 
module.exports = router;


Javascript




// models/Event.js
const mongoose = require('mongoose');
 
const eventSchema = new mongoose.Schema({
    title: { type: String, required: true },
    date: { type: Date, required: true },
    reminder: { type: Boolean, default: false },
 
});
const Event = mongoose.model('Event', eventSchema);
 
module.exports = Event;


Steps to run the backend:

node server.js

Steps to Setup Frontend with React

Step 1: Create React App:

npx create-react-app event-management-frontend

Step 2: Switch to the project directory:

cd event-management-frontend

Step 3: Installing the required packages:

npm install axios

Project Structure:

Screenshot-2566-12-29-at-154953

Frontend Project Structure

The updated dependencies in package.json for frontend will look like:

"dependencies": {
"axios": "^1.5.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Example: Below is the code example of the frontend.

Javascript




// src/App.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import EventForm from './components/EventForm';
import EventList from './components/EventList';
import './App.css'
 
 
const App = () => {
    const [events, setEvents] = useState([]);
 
    useEffect(() => {
        // Fetch events from the server
        axios.get('http://localhost:5000/api/events')
            .then(response => setEvents(response.data))
            .catch(error => console.error(error));
    }, []);
 
    const handleEventAdd = (newEvent) => {
        setEvents([...events, newEvent]);
    };
 
    const handleEventDelete = (id) => {
        console.log("delete event " + id)
        // Delete an event
        axios.delete(`http://localhost:5000/api/events/${id}`)
            .then(
                () =>
                    setEvents(events.filter(event => event._id !== id)))
            .catch(error => console.error(error));
    };
 
    const handleToggleReminder = (eventId) => {
        // console.log('HI');
 
        // Find the event by ID
        const selectedEvent =
            events.find(event => event._id === eventId);
 
        // Toggle the reminder status
        const updatedEvent =
        {
            ...selectedEvent,
            reminder: !selectedEvent.reminder
        };
 
        // console.log('Updated',updatedEvent);
 
 
        // Update the event in the database
        axios.put(`http://localhost:5000/api/events/${eventId}`, updatedEvent)
            .then(response => {
                // console.log('res',response.data);
 
                // If the update is successful, update the events in the state
                const updatedEvents = events.map(event =>
                    event._id === eventId ? updatedEvent : event
                );
                setEvents(updatedEvents);
            })
            .catch(
                error =>
                    console.error(`Error updating reminder status for
                event with ID ${eventId}:`, error));
    };
 
    const onEventEdit = (eventId, updatedData) => {
        // Update the event in the database
        axios.put(`http://localhost:5000/api/events/${eventId}`, updatedData)
            .then(response => {
                // If the update is successful, update the events in the state
                const updatedEvents = events.map(event =>
                    event._id ===
                        eventId ?
                        { ...event, ...updatedData } : event
                );
                setEvents(updatedEvents);
            })
            .catch(
                error =>
                    console.error(`Error updating event with
                        ID ${eventId}:`, error)
            );
    };
 
    return (
        <div className='main-container'>
            <h1 className='gfg'>
                GFG
            </h1>
            <h2>Event Management App</h2>
            <EventForm onEventAdd={handleEventAdd} />
            <EventList
                events={events}
                onEventDelete={handleEventDelete}
                onToggleReminder={handleToggleReminder}
                onEventEdit={onEventEdit}
            />
        </div>
    );
};
 
export default App;


Javascript




// src/EventList.js
import React, { useState } from 'react';
// Import the new EventItem component
import EventItem from './EventItem';
 
 
const EventList = (
    { events, onEventDelete,
        onToggleReminder, onEventEdit
    }
) => {
    const [editedEvents, setEditedEvents] = useState([]);
 
    const handleEventEdit = (eventId, updatedData) => {
        // Find the index of the event being edited
        const eventIndex =
            editedEvents
                .findIndex(
                    event =>
                        event._id === eventId
                );
 
        if (eventIndex !== -1) {
            // Update the edited event in the local state
            const updatedEditedEvents = [...editedEvents];
            updatedEditedEvents[eventIndex] = {
                ...updatedEditedEvents[eventIndex],
                ...updatedData,
            };
 
            setEditedEvents(updatedEditedEvents);
        } else {
            // If the event is not already in the local state, add it
            setEditedEvents(
                [...editedEvents,
                { _id: eventId, ...updatedData }
                ]
            );
        }
        // Pass the edit request to the parent component
        onEventEdit(eventId, updatedData);
    };
 
    return (
        <div className="event-list">
            {events.map(event => (
                <EventItem
                    key={event._id}
                    event={
                        editedEvents
                            .find(
                                editedEvent =>
                                    editedEvent._id === event._id) || event
                    }
                    onToggleReminder={onToggleReminder}
                    onEventDelete={onEventDelete}
                    onEventEdit={handleEventEdit}
                />
            ))}
        </div>
    );
};
 
export default EventList;


Javascript




// src/EventItem.js
import React, { useEffect, useState } from 'react';
import moment from 'moment';
 
 
const EventItem = (
    { event, onEventDelete,
        onToggleReminder, onEventEdit
    }) => {
    const [isEditing, setIsEditing] = useState(false);
    const [editedTitle, setEditedTitle] = useState(event.title);
    const [editedDate, setEditedDate] =
        useState(moment(event.date).format("YYYY-MM-DD"));
    const [rem, setRem] = useState("")
 
 
    useEffect(() => {
        if (event) {
            setRem(event.reminder ? "" : "Reminder On");
 
            // Check if the event is today and has a reminder
            const today = new Date();
            const eventDate = new Date(event.date);
 
            today.setHours(0, 0, 0, 0);
            eventDate.setHours(0, 0, 0, 0);
 
            if (today.getTime() ===
                eventDate.getTime() &&
                event.reminder) {
                alert(`Today is the day of the event:
                ${event.title}`);
            }
        } else {
            setRem("Reminder On");
        }
    }, [event, event.reminder]);
 
    const handleEditClick = () => {
        setIsEditing(true);
    };
 
    const handleSaveClick = () => {
 
        // Perform the update in the database (you may use an API request here)
        onEventEdit(event._id,
            {
                title: editedTitle,
                date: editedDate
            });
 
        // Exit the edit mode
        setIsEditing(false);
    };
 
    const handleCancelClick = () => {
        // Reset the edited values and exit the edit mode
        setEditedTitle(event.title);
        setEditedDate(moment(event.date)
            .format("YYYY-MM-DD"));
        setIsEditing(false);
    };
 
    return (
        <div className="event-card">
 
            <p className='rem-para'>
                {
                    event.reminder ? "Reminder On" : ""
                }
            </p>
 
 
            <div className="event-info">
 
                {isEditing ? (
                    <>
                        <input
                            type="text"
                            value={editedTitle}
                            onChange={
                                (e) =>
                                    setEditedTitle(e.target.value)
                            }
                        />
                        <input
                            type="date"
                            value={editedDate}
                            onChange={
                                (e) =>
                                    setEditedDate(e.target.value)
                            }
                        />
                    </>
                ) : (
                    <>
                        <h3 className="event-title">{event.title}</h3>
                        <hr />
                        <span className="event-date">
 
                            <span style={{ "fontWeight": "700" }}>
                                Event On:
                            </span>
                            {
                                moment(event.date)
                                    .add(1, 'days').calendar()
                            };
                        </span>
                    </>
                )}
            </div>
            <div className="event-actions">
                {isEditing ? (
                    <>
                        <button onClick={handleSaveClick}>
                            Save
                        </button>
                        <button onClick={handleCancelClick}>
                            Cancel
                        </button>
                    </>
                ) : (
                    <>
                        <button onClick={
                            () => onToggleReminder(event._id)
                        }>
                            {
                                event.reminder ?
                                    'Disable Reminder' : 'Enable Reminder'
                            }
                        </button>
                        <button className='delete-btn'
                            onClick={
                                () => onEventDelete(event._id)}>
                            Delete
                        </button>
                        <button onClick={handleEditClick}>
                            Edit
                        </button>
                    </>
                )}
            </div>
        </div>
    );
};
 
export default EventItem;


Javascript




// src/EventForm.js
import React, { useState } from 'react';
import axios from 'axios';
import './EventForm.css';
 
const EventForm = ({ onEventAdd }) => {
    const [newEvent, setNewEvent] =
        useState({ title: '', date: '', reminder: false });
 
    const handleInputChange = (e) => {
        setNewEvent(
            {
                ...newEvent,
                [e.target.name]: e.target.value
            }
        );
    };
 
    const handleSubmit = (e) => {
        e.preventDefault();
 
        // Create a new event
        axios.post('http://localhost:5000/api/events', newEvent)
            .then(response => {
                onEventAdd(response.data);
                setNewEvent({ title: '', date: '', reminder: false });
            })
            .catch(error => console.error(error));
    };
    return (
        <form onSubmit={handleSubmit}>
            <label>Title:</label>
            <input type="text" name="title"
                value={newEvent.title}
                onChange={handleInputChange} required />
            <label>Date:</label>
            <input type="date"
                name="date" value={newEvent.date}
                onChange={handleInputChange} required />
 
            <button type="submit">Add Event</button>
        </form>
    );
};
export default EventForm;


CSS




/* src/EventList.css */
.event-list {
    display: flex;
    flex-wrap: wrap;
}
 
.event-card {
    background-color: #D2E3C8;
    border: 1px solid #ddd;
    border-radius: 8px;
    margin: 10px;
    padding: 15px;
    width: 200px;
    overflow: hidden;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
 
.event-card:hover {
    box-shadow: 0 4px 8px green;
}
 
.event-info {
    margin-bottom: 10px;
}
 
.event-title {
    font-weight: bold;
}
 
.event-date {
    color: #555;
}
 
.event-actions {
    display: flex;
    justify-content: space-between;
}
 
.delete-btn:hover {
    background-color: red;
    color: white;
 
}
 
.rem-para {
    background-color: green;
    color: white;
    padding: 2px;
    width: fit-content;
 
    position: relative;
    left: -1px;
    bottom: 22px;
 
}
 
.gfg {
    padding: 15px;
    color: white;
    background-color: rgb(6, 162, 6);
    border-radius: 25px;
}
 
 
/* form
   */
 
input {
    padding: 5px;
    width: 500px;
}
 
form {
    display: flex;
    flex-direction: column;
    justify-content: center;
    border: 2px solid red;
    padding: 20px;
    border-radius: 10px;
    gap: 5px;
    background: linear-gradient(to right, #FFA500, #FF6347);
    ;
}
 
.main-container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}
 
label {
    font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
    font-weight: 500;
}


Steps to run the app:

npm start

Output:

Untitled-design-(20)

Final Output



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads