Web-Dev-101 - Walkthrough
Web-Dev-101 - Walkthrough
6. Create a new folder called components and create the below files:
CreateEvent.jsx
ViewEvents.jsx
EditEvent.jsx
EventCard.jsx
function AppRouter() {
return (
<Router>
<Routes>
<Route path="/" element={<App/>}>
<Route index element={<ViewEvents/>}/>
<Route path="/events" element={<ViewEvents/>}/>
<Route path="/add-event" element={<CreateEvent/>}/>
<Route path="/update-event/:id" element={<EditEvent/>}/>
</Route>
</Routes>
</Router>
)
}
function App() {
return (
<>
<Navbar/>
<Outlet/>
</>
)
}
createRoot(document.getElementById('root')).render(
<StrictMode>
<App/>
</StrictMode>,
)
After:
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'
import AppRouter from './Router.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<AppRouter/>
</StrictMode>,
)
10. Now let us create a simple navbar for our web application
● First create Navbar.css file
function Navbar() {
return (
<nav className="navbar">
<h2>Event Planner</h2>
<ul>
<li><Link to="/events">View Events</Link></li>
<li><Link to="/add-event">Add Event</Link></li>
</ul>
</nav>
)
}
.navbar h2 {
margin: 0;
font-size: 20px;
white-space: nowrap;
}
.navbar ul {
list-style: none;
display: flex;
gap: 15px;
margin: 0;
padding: 0;
}
.navbar li {
display: inline;
}
.navbar a {
text-decoration: none;
color: white;
font-weight: bold;
white-space: nowrap;
}
.navbar a:hover {
text-decoration: underline;
}
● Now make css file CreateEvent.css to add styles to the form and import to
CreateEvent.jsx
import './CreateEvent.css'
function CreateEvent() {
const {register,handleSubmit,formState:{errors},} = useForm();
return (
<div>
<h2>Create Event</h2>
<form>
<label>Event Name:</label>
<input type="text" name="" id="" {...register("name",{required:'Event name is
required'})}/>
{errors.name && <p className="error">{errors.name.message}</p>}
<label>Date:</label>
<input type="date" name="" id="" {...register("date",{required:'Date is
required'})}/>
{errors.date && <p className="error">{errors.date.message}</p>}
<label>Time:</label>
<input type="time" name="" id="" {...register("time", { required: "Time is
required" })}/>
{errors.time && <p className="error">{errors.time.message}</p>}
<label>Venue</label>
<input type="text" name="" id="" {...register("venue", { required: "Venue is
required" })} />
{errors.venue && <p className="error">{errors.venue.message}</p>}
.parent-container{
display: flex;
justify-content: center;
align-items: center;
margin-top: 100px;
}
.form-container {
width: 400px;
padding: 20px;
border: 1px solid #ccc;
border-radius: 8px;
color: black;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
background-color: #fff;
text-align: center;
}
h2 {
margin-bottom: 20px;
}
form {
display: flex;
flex-direction: column;
}
label {
font-weight: bold;
margin: 10px 0 5px;
}
input {
padding: 8px;
font-size: 16px;
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
}
button {
margin-top: 15px;
padding: 10px;
background-color: #007bff;
color: white;
font-size: 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
.error {
color: red;
font-size: 14px;
margin-top: 5px;
}
export { db };
The code for onSubmit to post the data to the firebase storage:
const onSubmit = async (data)=>{
try {
const docRef = await addDoc(collection(db, "events"), {
eventName: data.name,
date: data.date,
time: data.time,
venue: data.venue,
createdAt: new Date()
});
console.log("Document written with ID:", docRef.id);
alert("Event Added")
} catch (error) {
console.error("Error adding document:", error);
}
}
12. Now we will create the card to display details about each event in CreateEvent.jsx:
Code:
import React from 'react'
import './EventCard.css'
<div className="buttons">
<button className="edit-btn">Edit</button>
<button className="delete-btn">Delete</button>
</div>
</div>
);
};
p{
margin: 4px 0;
color: #555;
}
.buttons {
margin-top: 12px;
display: flex;
justify-content: center;
gap: 10px;
}
.edit-btn, .delete-btn {
padding: 8px 12px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
.edit-btn {
background-color: #007bff;
color: white;
}
.edit-btn:hover {
background-color: #0056b3;
}
.delete-btn {
background-color: #dc3545;
color: white;
}
.delete-btn:hover {
background-color: #b02a37;
}
13. Now create the ViewEvents.jsx file to show all events which have been created
Code:
import React from "react";
import './ViewEvents.css'
import { useState, useEffect } from "react";
import { collection, getDocs } from "firebase/firestore";
import { db } from "../firebaseConfig";
import EventCard from "./EventCard";
import "./ViewEvents.css";
useEffect(() => {
const fetchEvents = async () => {
try {
const querySnapshot = await getDocs(collection(db, "events"));
const eventsList = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() }));
setEvents(eventsList);
} catch (error) {
console.error("Error fetching events:", error);
}
};
fetchEvents();
}, [events]);
return (
<div className="view-events">
{events.length > 0 ? (
<div className="events-grid">
{events.map(event => (
<EventCard key={event.id} event={event} />
))}
</div>
):(
<p className="no-events">No events available</p>
)}
</div>
);
};
export default ViewEvents;
● Now create the ViewEvents.css file to style the components, and link it to the
ViewEvents.jsx code
CSS:
.view-events {
text-align: center;
margin-top: 30px;
padding: 20px;
}
h2 {
margin-bottom: 20px;
color: #333;
}
.events-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
justify-content: center;
padding: 20px;
}
● Modify EventCard.jsx file to pass the delete and edit functions, and call them
when buttons are clicked:
const EventCard = ({ event ,onDelete,onEdit}) => {
return (
<div className="event-card">
<h3>{event.eventName}</h3>
<p><strong>Date:</strong> {event.date}</p>
<p><strong>Time:</strong> {event.time}</p>
<p><strong>Venue:</strong> {event.venue}</p>
<div className="buttons">
<button className="edit-btn" onClick={() => onEdit(event)}>Edit</button>
<button className="delete-btn"onClick={() =>
onDelete(event)}>Delete</button>
</div>
</div>
);
};
● Now pass the functions in ViewEvents.jsx:
{events.map(event => (
<EventCard key={event.id} event={event}
onDelete={handleDelete} onEdit={handleEdit}/>
))}
function EditEvent() {
const { id } = useParams();
const navigate = useNavigate();
const { register, handleSubmit, setValue ,formState:{errors}} = useForm();
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchEvent = async () => {
try {
console.log("Fetching event with ID:", id);
const docRef = doc(db, "events", id);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
const eventData = docSnap.data();
console.log("Event data:", eventData)
// Populate form fields with existing data
setValue("eventName", eventData.eventName);
setValue("date", eventData.date);
setValue("time", eventData.time);
setValue("venue", eventData.venue);
setEventLoaded(true);
} else {
setError("Event not found");
}
} catch (error) {
console.error("Error fetching event:", error);
setError("Failed to load event");
}
};
fetchEvent();
}, [id, setValue]);
<label>Date:</label>
<input type="date" name="" id="" {...register("date",{required:'Date is
required'})}/>
{errors.date && <p className="error">{errors.date.message}</p>}
<label>Time:</label>
<input type="time" name="" id="" {...register("time", { required: "Time is
required" })}/>
{errors.time && <p className="error">{errors.time.message}</p>}
<label>Venue</label>
<input type="text" name="" id="" {...register("venue", { required: "Venue is
required" })} />
{errors.venue && <p className="error">{errors.venue.message}</p>}