KEMBAR78
Final Project | PDF | Databases | Computing
0% found this document useful (0 votes)
12 views11 pages

Final Project

The document outlines the core features and requirements for an event management website, including user authentication, event management, a booking system, and admin controls. It specifies frontend and backend requirements, database models, optional advanced features, testing protocols, deployment options, and compliance measures. Additionally, it provides a React component for event listing and booking functionalities, along with server-side booking logic using Node.js and MongoDB.

Uploaded by

tejatarun770
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views11 pages

Final Project

The document outlines the core features and requirements for an event management website, including user authentication, event management, a booking system, and admin controls. It specifies frontend and backend requirements, database models, optional advanced features, testing protocols, deployment options, and compliance measures. Additionally, it provides a React component for event listing and booking functionalities, along with server-side booking logic using Node.js and MongoDB.

Uploaded by

tejatarun770
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 11

Core Features & Requirements for the Event Management Website

🔐 User Authentication
Registration & login system

Secure authentication using JWT or OAuth

📅 Event Management
Create, update, and delete events

Store and display event details (title, date, location, description, price, etc.)

🧾 Booking System
Users can book tickets

Handle payments (simulation or integration)

Store booking records in the database

👤 User Dashboard
View booked events

Manage bookings

Receive notifications

🧰 Admin Controls
Admin dashboard to:

Manage events

Monitor user activity

View analytics

🌐 Frontend Requirements
Responsive UI

UI built with React.js

Design follows UI/UX best practices

🔧 Backend Requirements
Built with Node.js and Express

Use of a database (MongoDB or SQL)

Develop RESTful APIs for:

User management

Event handling

Booking system

Payments

💾 Database Requirements
Models for:
Users

Events

Bookings

Transactions (optional)

📊 Advanced Features (Optional but Encouraged)


✅ Event recommendations based on user interests

✅ Advanced search & filtering

✅ User preferences & bookmarks

✅ Commenting system

✅ Social media sharing

✅ Real-time updates (e.g., new events shown live)

✅ Admin analytics dashboard

🧪 Testing
Unit tests

Integration tests (e.g., Jest or Mocha)

🚀 Deployment
Deployed on hosting platforms like:

Netlify (frontend)

Heroku/AWS/Vercel (backend)

📄 Documentation
User manual

API documentation

Setup instructions for developers

🔐 Compliance & Maintenance


Monitor performance

Ensure data privacy (GDPR, CCPA)

import React, { useEffect, useState, useCallback } from 'react';


import { useNavigate } from 'react-router-dom';
import API from '../api/api';
import { toast } from 'react-toastify';
import './eventList.css';

const categoryColors = {
Conference: 'conference',
Workshop: 'workshop',
Webinar: 'webinar',
Meetup: 'meetup',
Singing: 'singing',
Dancing: 'dancing',
Other: 'other',
};

const categoryIcons = {
Conference: '',
Workshop: '',
Webinar: '💻',
Meetup: '🤝',
Singing: '🎤',
Dancing: '💃',
Other: '📌',
};

const EventList = () => {


const [events, setEvents] = useState([]);
const [editEvent, setEditEvent] = useState(null);
const [formData, setFormData] = useState({
title: '', description: '', date: '', location: '', price: '', seats: '',
category: 'Other'
});
const [showPayment, setShowPayment] = useState(false);
const [paymentData, setPaymentData] = useState({});
const [processing, setProcessing] = useState(false);
const [cardInfo, setCardInfo] = useState({
cardNumber: '',
nameOnCard: '',
expiry: '',
cvv: ''
});

const [filters, setFilters] = useState({


search: '',
category: '',
startDate: '',
endDate: '',
sort: 'latest'
});

const navigate = useNavigate();


const isAdmin = localStorage.getItem('role') === 'admin';

const fetchEvents = useCallback(() => {


const query = new URLSearchParams();
if (filters.search) query.append('search', filters.search);
if (filters.category) query.append('category', filters.category);
if (filters.startDate) query.append('startDate', filters.startDate);
if (filters.endDate) query.append('endDate', filters.endDate);
if (filters.sort) query.append('sort', filters.sort);

API.get(`/events?${query.toString()}`)
.then(res => setEvents(res.data))
.catch(() => toast.error('❌ Failed to load events'));
}, [filters]);

useEffect(() => {
fetchEvents();
}, [fetchEvents]);

const handleFilterChange = (e) => {


setFilters({ ...filters, [e.target.name]: e.target.value });
};

const openPaymentModal = (event, seats) => {


setPaymentData({ event, seats, total: (event.price || 0) * seats });
setShowPayment(true);
};

const handleBook = async (eventId, maxSeats) => {


const token = localStorage.getItem('token');
if (!token) {
toast.warn('⚠️ Please login to book');
navigate('/login');
return;
}

const seats = prompt(`Enter number of seats (1 - ${maxSeats}):`);


const seatsBooked = parseInt(seats);

if (!seats || isNaN(seatsBooked) || seatsBooked < 1 || seatsBooked > maxSeats)


{
toast.warn(`⚠️ Enter valid seats between 1 and ${maxSeats}`);
return;
}

const selectedEvent = events.find(e => e._id === eventId);


if (!selectedEvent) {
toast.error('❌ Event not found');
return;
}

// ✅ Skip payment modal for free events


if (!selectedEvent.price || selectedEvent.price === 0) {
try {
await API.post('/bookings',
{ event: selectedEvent._id, seatsBooked, paymentType: 'Free' },
{ headers: { Authorization: `Bearer ${token}` } }
);
toast.success('✅ Free Event Booked Successfully');
fetchEvents();
} catch (err) {
toast.error('❌ Booking failed');
}
return;
}

// If paid event, open payment modal


openPaymentModal(selectedEvent, seatsBooked);
};

const isValidCardDetails = () => {


const { cardNumber, nameOnCard, expiry, cvv } = cardInfo;
const cardRegex = /^\d{16}$/;
const nameRegex = /^[a-zA-Z ]{2,}$/;
const expiryRegex = /^(0[1-9]|1[0-2])\/\d{2}$/;
const cvvRegex = /^\d{3}$/;

if (!cardRegex.test(cardNumber)) {
toast.warning('⚠️ Card number must be 16 digits');
return false;
}
if (!nameRegex.test(nameOnCard)) {
toast.warning('⚠️ Enter a valid name');
return false;
}
if (!expiryRegex.test(expiry)) {
toast.warning('⚠️ Expiry must be MM/YY');
return false;
}
if (!cvvRegex.test(cvv)) {
toast.warning('⚠️ CVV must be 3 digits');
return false;
}
return true;
};

const confirmPayment = async () => {


const token = localStorage.getItem('token');
if (!isValidCardDetails()) return;

setProcessing(true);
setTimeout(async () => {
try {
await API.post('/bookings',
{ event: paymentData.event._id, seatsBooked: paymentData.seats,
paymentType: 'Credit Card' },
{ headers: { Authorization: `Bearer ${token}` } }
);
toast.success('✅ Payment & Booking Successful');
setShowPayment(false);
setCardInfo({ cardNumber: '', nameOnCard: '', expiry: '', cvv: '' });
fetchEvents();
} catch (err) {
toast.error('❌ Payment failed');
} finally {
setProcessing(false);
}
}, 1500);
};

const handleViewDetails = (eventId) => navigate(`/event/${eventId}`);

const handleDelete = async (eventId) => {


if (window.confirm('Are you sure you want to delete this event?')) {
try {
await API.delete(`/events/${eventId}`, {
headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
});
toast.success(' Event deleted');
fetchEvents();
} catch (err) {
toast.error('❌ Failed to delete event');
}
}
};

const handleEdit = (event) => {


setEditEvent(event._id);
setFormData({
title: event.title,
description: event.description,
date: event.date.substring(0, 10),
location: event.location,
price: event.price,
seats: event.seats,
category: event.category,
});
};

const handleUpdate = async () => {


try {
await API.put(`/events/${editEvent}`, formData, {
headers: { Authorization: `Bearer ${localStorage.getItem('token')}` },
});
toast.success('✏️ Event updated');
setEditEvent(null);
fetchEvents();
} catch (err) {
toast.error('❌ Failed to update event');
}
};

return (
<div className="event-wrapper">
<h2 className="event-heading">🎉 Explore Events</h2>

{/* Filter Bar */}


<div className="filter-bar">
<input
type="text"
name="search"
placeholder="🔍 Search events..."
value={filters.search}
onChange={handleFilterChange}
/>
<select name="category" value={filters.category}
onChange={handleFilterChange}>
<option value="">All Categories</option>
{Object.keys(categoryIcons).map(cat => (
<option key={cat} value={cat}>{cat}</option>
))}
</select>
<input type="date" name="startDate" value={filters.startDate}
onChange={handleFilterChange} />
<input type="date" name="endDate" value={filters.endDate}
onChange={handleFilterChange} />
<select name="sort" value={filters.sort} onChange={handleFilterChange}>
<option value="latest">Latest</option>
<option value="oldest">Oldest</option>
</select>
</div>

{/* Event Grid */}


<div className="event-grid">
{events.map(e => {
const category = e.category || 'Other';
const tagClass = categoryColors[category] || 'other';
const icon = categoryIcons[category] || '📌';

return (
<div key={e._id} className="event-card">
<span className={`event-tag ${tagClass}`}>
{icon} {category}
</span>
<h3 className="event-title">{e.title}</h3>
<p className="event-desc">{e.description.substring(0, 100)}...</p>
<div className="event-info">
<p><strong>Date:</strong> {new Date(e.date).toDateString()}</p>
<p><strong>Location:</strong> {e.location}</p>
<p><strong>Price:</strong> ₹{e.price || 'Free'}</p>
<p><strong>Seats Left:</strong> {e.seats}</p>
</div>
<div className="event-actions">
<button
onClick={() => handleBook(e._id, e.seats)}
disabled={e.seats === 0}
className={e.seats === 0 ? 'btn disabled' : 'btn book'}
>
{e.seats === 0 ? 'Sold Out' : 'Book'}
</button>
<button onClick={() => handleViewDetails(e._id)} className="btn
details">View Details</button>
{isAdmin && (
<>
<button onClick={() => handleEdit(e)} className="btn
edit">Edit</button>
<button onClick={() => handleDelete(e._id)} className="btn
delete">Delete</button>
</>
)}
</div>
</div>
);
})}
</div>

{/* Payment Modal */}


{showPayment && (
<div className="payment-modal">
<div className="payment-box">
<h3>💳 Simulated Payment</h3>
<p><strong>Event:</strong> {paymentData.event.title}</p>
<p><strong>Seats:</strong> {paymentData.seats}</p>
<p><strong>Total:</strong> ₹{paymentData.total}</p>
<input placeholder="1234 5678 9012 3456" value={cardInfo.cardNumber}
onChange={(e) => setCardInfo({ ...cardInfo, cardNumber: e.target.value })} />
<input placeholder="Name on Card" value={cardInfo.nameOnCard}
onChange={(e) => setCardInfo({ ...cardInfo, nameOnCard: e.target.value })} />
<input placeholder="MM/YY" value={cardInfo.expiry} onChange={(e) =>
setCardInfo({ ...cardInfo, expiry: e.target.value })} />
<input placeholder="CVV" value={cardInfo.cvv} onChange={(e) =>
setCardInfo({ ...cardInfo, cvv: e.target.value })} />
<button onClick={confirmPayment} className="pay-btn"
disabled={processing}>{processing ? 'Processing...' : `Pay ₹$
{paymentData.total}`}</button>
<button onClick={() => setShowPayment(false)} className="cancel-
btn">Cancel</button>
</div>
</div>
)}

{/* Edit Form */}


{editEvent && (
<div className="edit-form">
<h3>✏️ Edit Event</h3>
<input value={formData.title} onChange={e => setFormData({ ...formData,
title: e.target.value })} placeholder="Title" />
<textarea value={formData.description} onChange={e =>
setFormData({ ...formData, description: e.target.value })}
placeholder="Description" />
<input type="date" value={formData.date} onChange={e =>
setFormData({ ...formData, date: e.target.value })} />
<input value={formData.location} onChange={e =>
setFormData({ ...formData, location: e.target.value })} placeholder="Location" />
<input type="number" value={formData.price} onChange={e =>
setFormData({ ...formData, price: e.target.value })} placeholder="Price" />
<input type="number" value={formData.seats} onChange={e =>
setFormData({ ...formData, seats: e.target.value })} placeholder="Seats" />
<select value={formData.category} onChange={e =>
setFormData({ ...formData, category: e.target.value })}>
{Object.keys(categoryIcons).map(cat => (
<option key={cat} value={cat}>{cat}</option>
))}
</select>
<button onClick={handleUpdate} className="btn update">Save</button>
<button onClick={() => setEditEvent(null)} className="btn
cancel">Cancel</button>
</div>
)}
</div>
);
};

export default EventList;

import Booking from '../models/Booking.js';


import Event from '../models/Event.js';
import User from '../models/User.js'; // Optional
import mongoose from 'mongoose';

// ✅ Book an Event with free event payment type handling


export const bookEvent = async (req, res) => {
try {
const { event, seatsBooked, paymentType } = req.body;

if (!event || !seatsBooked) {
return res.status(400).json({ message: 'Event and seat count required' });
}
const foundEvent = await Event.findById(event);
if (!foundEvent) {
return res.status(404).json({ message: 'Event not found' });
}

if (seatsBooked > foundEvent.seats) {


return res.status(400).json({ message: `Only ${foundEvent.seats} seats
available` });
}

// ✅ Auto-set paymentType to 'Free' if event is free


let finalPaymentType = paymentType || 'Credit Card';
if (foundEvent.price === 0) {
finalPaymentType = 'Free';
}

const booking = new Booking({


event,
seatsBooked,
user: req.user._id,
paymentType: finalPaymentType,
status: 'Booked'
});

await booking.save();

foundEvent.seats -= seatsBooked;
await foundEvent.save();

const io = req.app.get('io');
io.emit('notification', {
type: 'booking',
message: ` New booking by user ${req.user._id} for "${foundEvent.title}"`,
timestamp: new Date(),
});

res.status(201).json({ message: 'Event booked successfully' });


} catch (error) {
console.error('Booking error:', error);
res.status(500).json({ message: 'Booking failed', error });
}
};

// ✅ Get All Bookings of Logged-in User (with safe deleted event handling)
export const getMyBookings = async (req, res) => {
try {
const bookings = await Booking.find({ user: req.user._id }).populate('event');

const sanitizedBookings = bookings.map(b => {


const plainBooking = b.toObject();
if (!b.event) {
plainBooking.eventDeleted = true;
}
return plainBooking;
});

res.status(200).json(sanitizedBookings);
} catch (error) {
console.error('Fetch bookings error:', error);
res.status(500).json({ message: 'Failed to fetch your bookings', error });
}
};

// ✅ Cancel a Booking with ObjectId validation and safe event restoration


export const cancelBooking = async (req, res) => {
try {
const bookingId = req.params.id;

if (!mongoose.Types.ObjectId.isValid(bookingId)) {
return res.status(400).json({ message: 'Invalid booking ID format' });
}

const booking = await Booking.findById(bookingId).populate('event');


if (!booking) {
return res.status(404).json({ message: 'Booking not found' });
}

if (booking.user.toString() !== req.user._id.toString()) {


return res.status(403).json({ message: 'Unauthorized to cancel this
booking' });
}

if (booking.status === 'Canceled') {


return res.status(200).json({ message: 'Booking was already canceled' });
}

booking.status = 'Canceled';
await booking.save();

if (booking.event) {
booking.event.seats += booking.seatsBooked;
await booking.event.save();

const io = req.app.get('io');
io.emit('notification', {
type: 'cancel',
message: `❌ Booking for "${booking.event.title}" cancelled by user $
{req.user._id}`,
timestamp: new Date(),
});
}

res.status(200).json({ message: 'Booking cancelled successfully' });


} catch (error) {
console.error('Cancellation error:', error);
res.status(500).json({ message: 'Cancellation failed', error });
}
};

// ✅ Get Booking by ID with safe deleted event flag


export const getBookingById = async (req, res) => {
try {
const bookingId = req.params.id;

if (!mongoose.Types.ObjectId.isValid(bookingId)) {
return res.status(400).json({ message: 'Invalid booking ID format' });
}
const booking = await Booking.findById(bookingId)
.populate('event')
.populate('user', 'name email');

if (!booking) {
return res.status(404).json({ message: 'Booking not found' });
}

if (booking.user._id.toString() !== req.user._id.toString()) {


return res.status(403).json({ message: 'Unauthorized to view this ticket' });
}

const sanitizedBooking = booking.toObject();


if (!booking.event) {
sanitizedBooking.eventDeleted = true;
}

res.status(200).json(sanitizedBooking);
} catch (error) {
console.error('Fetch booking by ID error:', error);
res.status(500).json({ message: 'Failed to fetch booking', error });
}
};

You might also like