40 KiB
Agenda
We will try to cover most of these topics in today's sessions and the remaining in the next.
- Build the shows components
- Build the seating arrangements
- Book tickets
- Make Payments
- Deploy It is going to be a bit challenging, advanced, but very interesting session covering topics that are asked very frequently in interviews.
So let's start.
Handle the Update and Delete Functionalities
In the button.js add the following code: import React from "react";
function Button({ title, onClick, variant, disabled, fullWidth, type }) {
let className = "bg-primary p-1 text-white";
if (fullWidth) {
className += " w-full";
}
if (variant === "outlined") {
className = className.replace(
"bg-primary",
"border border-primary text-primary bg-white"
);
}
return (
<button
className = {className}
type = {type}
onClick = {onClick}
disabled = {disabled}
>
{title}
</button>
);
}
export default Button;
The provided React component, named Button
, is a reusable button element with customizable styles. Here's an explanation of the code:
-
Props:
The component accepts various props for customization, includingtitle
(button text),onClick
(click event handler),variant
(button style),disabled
(disabling the button),fullWidth
(expands button to full width), andtype
(button type, e.g., submit or button). -
Conditional Styling:
The component dynamically applies CSS classes based on the props. It defaults to a primary background color and white text. IffullWidth
is true, it expands to full width. Ifvariant
is "outlined," it changes to a bordered style with different text and background colors. -
Button Element:
The component renders an HTML button element with the defined styles and properties, making it versatile for various UI button needs. -
Reusability:
This component promotes code reusability by allowing developers to create buttons with different styles and behaviors based on the provided props. It simplifies button creation in React applications.
In the theaterRoute.js file lets set the routes for the update and delete buttons as follows:
//update theatre
router.put("/update-theatre",authMiddleware ,async(req,res) => {
try{
await Theatre.findByIdAndUpdate(req.body.theatreId,req.body);
res.send({
success:true,
message:"Theatre updated"
})
}catch(err){
res.send({
success:false,
message:err.message
})
}
})
//delete a theatre
router.post('/delete-theatre', authMiddleware,async (req,res) => {
try{
await Theatre.findByIdAndDelete(req.body.theatreId)
res.send({
success:true,
message:"Theatre Deleted"
})
}catch(err){
res.send({
success:false,
message:err.message
})
}
})
These Express.js router endpoints handle theater-related operations such as updating and deleting theaters. Here's a detailed explanation:
-
Update Theatre (PUT /update-theatre):
- This route is accessible only to authenticated users due to the 'authMiddleware'.
- It receives a request containing the theater ID (
theatreId
) and new theater data (req.body
). - Using
Theatre.findByIdAndUpdate
, it updates the theater in the database based on the provided theater ID. - Upon a successful update, it responds with a success message, indicating that the theater has been updated.
- In case of an error (e.g., database update failure), it sends a failure response with an error message.
-
Delete Theatre (POST /delete-theatre):
- Similarly, this route is protected by 'authMiddleware' for authenticated access.
- It accepts a request with the theater ID (
theatreId
) to be deleted. - Utilizing
Theatre.findByIdAndDelete
, it removes the specified theater from the database. - Upon successful deletion, it responds with a success message, confirming that the theater has been deleted.
- In the event of an error (e.g., database deletion failure), it returns a failure response along with an error message.
These routes provide essential functionality for managing theater data, enabling updates and deletions while ensuring user authentication.
Also set the api calls in the theater.js files for the update and delete as follows:
export const UpdateTheatre = async (payload) => {
try{
const response = await axiosInstance.put('/api/theatres/update-theatre',payload);
return response.data;
}catch(err){
return err.response;
}
}
export const DeleteTheatre = async(payload) => {
try{
const response = await axiosInstance.post('/api/theatres/delete-theatre',payload);
return response.data
}catch(err){
return err.message
}
}
These JavaScript functions facilitate client-side communication with the server to update and delete theaters using Axios:
-
UpdateTheatre:
- This function sends a PUT request to the server's '/api/theatres/update-theatre' endpoint with a payload containing theater data to be updated.
- Upon success, it returns the response data from the server.
- In case of an error, it returns the error response received.
-
DeleteTheatre:
- It sends a POST request to the server's '/api/theatres/delete-theatre' endpoint, including the theater ID in the payload for deletion.
- If the deletion is successful, it returns the response data.
- In case of an error, it returns an error message.
These functions abstract the HTTP requests needed for updating and deleting theaters, allowing the client application to interact with the server seamlessly while handling potential errors gracefully.
Let's also update the delete and update functionalities and the getdata() in TheaterList.js file as follows:
import React, { useEffect, useState } from "react";
import Button from "../../components/Button";
import { useNavigate } from "react-router-dom";
import TheatreForm from "./TheatresForm";
import {
DeleteTheatre,
GetAllTheatres,
GetAllTheatresByOwner,
} from "../../apicalls/theatres";
import { useDispatch, useSelector } from "react-redux";
import { HideLoading, ShowLoading } from "../../redux/loadersSlice";
import { message, Table } from "antd";
import Shows from "./Shows";
function TheatresList() {
const { user } = useSelector((state) => state.users);
const [showTheatreFormModal = false, setShowTheatreFormModal] =
useState(false);
const [selectedTheatre = null, setSelectedTheatre] = useState(null);
const [formType = "add", setFormType] = useState("add");
const [theatres, setTheatres] = useState([]);
const [openShowsModal = false, setOpenShowsModal] = useState(false);
const dispatch = useDispatch();
const navigate = useNavigate();
const getData = async () => {
try {
dispatch(ShowLoading());
const response = await GetAllTheatresByOwner({
owner: user._id,
});
if (response.success) {
setTheatres(response.data);
} else {
message.error(response.message);
}
dispatch(HideLoading());
} catch (error) {
dispatch(HideLoading());
message.error(error.message);
}
};
const handleDelete = async (id) => {
try {
dispatch(ShowLoading());
const response = await DeleteTheatre({ theatreId: id });
if (response.success) {
message.success(response.message);
getData();
} else {
message.error(response.message);
}
dispatch(HideLoading());
} catch (error) {
dispatch(HideLoading());
message.error(error.message);
}
};
const columns = [
{
title: "Name",
dataIndex: "name",
},
{
title: "Address",
dataIndex: "address",
},
{
title: "Phone",
dataIndex: "phone",
},
{
title: "Email",
dataIndex: "email",
},
{
title: "Status",
dataIndex: "isActive",
render: (text, record) => {
if (text) {
return "Approved";
} else {
return "Pending / Blocked";
}
},
},
{
title: "Action",
dataIndex: "action",
render: (text, record) => {
return (
<div className = "flex gap-1 items-center">
<i
className = "ri-delete-bin-line"
onClick = {() => {
handleDelete(record._id);
}}
></i>
<i
className = "ri-pencil-line"
onClick = {() => {
setFormType("edit");
setSelectedTheatre(record);
setShowTheatreFormModal(true);
}}
></i>
{record.isActive && (
<span
className = "underline"
onClick = {() => {
setSelectedTheatre(record);
setOpenShowsModal(true);
}}
>
Shows
</span>
)}
</div>
);
},
},
];
useEffect(() => {
getData();
}, []);
return (
<div>
<div className = "flex justify-end mb - 1">
<Button
variant = "outlined"
title = "Add Theatre"
onClick = {() => {
setFormType("add");
setShowTheatreFormModal(true);
}}
/>
</div>
<Table columns = {columns} dataSource = {theatres} />
{showTheatreFormModal && (
<TheatreForm
showTheatreFormModal = {showTheatreFormModal}
setShowTheatreFormModal = {setShowTheatreFormModal}
formType = {formType}
setFormType = {setFormType}
selectedTheatre = {selectedTheatre}
setSelectedTheatre = {setSelectedTheatre}
getData = {getData}
/>
)}
{openShowsModal && (
<Shows
openShowsModal = {openShowsModal}
setOpenShowsModal = {setOpenShowsModal}
theatre = {selectedTheatre}
/>
)}
</div>
);
}
export default TheatresList;
Here's an explanation of the handleDelete
and update functionality in the TheatresList
component:
-
handleDelete Function:
- The
handleDelete
function is triggered when a user clicks the delete icon for a theater record. - It sends an asynchronous request to delete the theater using the
DeleteTheatre
API call. - Upon success, it displays a success message and then refreshes the list of theaters by calling the
getData
function. - In case of an error during deletion, it displays an error message.
- The
-
Update Functionality:
- The update functionality is initiated when a user clicks the edit icon for a theater record.
- It sets the
formType
to "edit" and populates theTheatreForm
with the details of the selected theater. - The user can modify the theater details and save the changes.
- Upon saving, it sends an asynchronous request to update the theater information using the
UpdateTheatre
API call. - If the update is successful, it displays a success message, closes the theater form modal, resets the selected theater, and refreshes the theater list by calling the
getData
function. - In case of an error during the update, it displays an error message.
These functionalities allow users to interact with theater records, enabling them to delete theaters they own and edit theater information as needed.
Implementation of the approval and rejection
For this first we want admin to see all the records in the theater space from all the users so lets start creating the table:
import React, { useEffect, useState } from "react";
import { GetAllTheatres, UpdateTheatre } from "../../apicalls/theatres";
import { useDispatch, useSelector } from "react-redux";
import { HideLoading, ShowLoading } from "../../redux/loadersSlice";
import { message, Table } from "antd";
function TheatreTable() {
const [theatres, setTheatres] = useState([]);
const dispatch = useDispatch();
const getData = async () => {
try {
dispatch(ShowLoading());
const response = await GetAllTheatres();
console.log(response.data);
if (response.success) {
setTheatres(response.data);
} else {
message.error(response.message);
}
dispatch(HideLoading());
} catch (error) {
dispatch(HideLoading());
message.error(error.message);
}
};
const handleStatusChange = async (theatre) => {
try {
dispatch(ShowLoading());
const response = await UpdateTheatre({
theatreId: theatre._id,
...theatre,
isActive: ! theatre.isActive,
});
if (response.success) {
message.success(response.message);
getData();
} else {
message.error(response.message);
}
dispatch(HideLoading());
} catch (error) {
dispatch(HideLoading());
message.error(error.message);
}
};
const columns = [
{
title: "Name",
dataIndex: "name",
},
{
title: "Address",
dataIndex: "address",
},
{
title: "Phone",
dataIndex: "phone",
},
{
title: "Email",
dataIndex: "email",
},
{
title: "Owner",
dataIndex: "owner",
render: (text, record) => {
return record.owner.name;
},
},
{
title: "Status",
dataIndex: "isActive",
render: (text, record) => {
if (text) {
return "Approved";
} else {
return "Pending / Blocked";
}
},
},
{
title: "Action",
dataIndex: "action",
render: (text, record) => {
return (
<div className = "flex gap-1">
{record.isActive && (
<span
className = "underline"
onClick = {() => handleStatusChange(record)}
>
Block
</span>
)}
{!record.isActive && (
<span
className = "underline"
onClick = {() => handleStatusChange(record)}
>
Approve
</span>
)}
</div>
);
},
},
];
useEffect(() => {
getData();
}, []);
return (
<div>
<Table columns = {columns} dataSource = {theatres} />
</div>
);
}
export default TheatreTable;
The TheatreTable
component manages and displays a table of theaters with the following functionality:
-
Data Fetching:
- Upon component rendering, it triggers the
getData
function, which sends an asynchronous request to the server to fetch all theaters using theGetAllTheatres
API call. - The retrieved theater data is displayed in a table.
- Upon component rendering, it triggers the
-
Status Change Handling:
- Each theater record in the table has an "Approve" or "Block" option in the "Status" column, depending on its current status.
- Users can change the status of a theater by clicking on the "Approve" or "Block" link.
- The
handleStatusChange
function sends an asynchronous request to update the theater's status using theUpdateTheatre
API call. - Upon success, it displays a success message, updates the status, and refreshes the theater list.
- If the update fails, it displays an error message.
-
Table Columns:
- The table displays theater details such as name, address, phone, email, owner, and status.
- The owner's name is fetched from the theater data.
- The status is displayed as "Approved" or "Pending / Blocked."
- The "Action" column allows users to change the theater's status.
Overall, this component provides an interface for administrators to manage and update the approval status of theaters efficiently.
Now set the theaterRoute to get the deatils of all the theaters:
//get all theatre route
router.get('/get-all-theatres',authMiddleware, async(req,res) => {
try{
const theatres = await Theatre.find().populate('owner');
res.send({
success:true,
message:"Theatres fetched",
data:theatres
})
}catch(err){
res.send({
success:false,
message:err.message
})
}
})
This route, accessible only to authenticated users due to the authMiddleware
, retrieves all theaters from the database. Key points include:
-
It uses the
Theatre
model to query the database for theaters. -
The
populate('owner')
method populates the theater's owner field, fetching owner details. -
If successful, it responds with a success message and the theater data.
-
In case of an error, it sends a failure message with an error description.
Building the Shows API
Now let's start creating the Shows API, that is when a theater gets approval then we give the options of shows, delete, and update like as shown below.
The outline of the Show api is as below:
Lets start creating this above functionalities in the profile folder like as:
In the theaterList.js do the needful as shown below:
import React, { useEffect, useState } from "react";
import Button from "../../components/Button";
import { useNavigate } from "react-router-dom";
import TheatreForm from "./TheatresForm";
import {
DeleteTheatre,
GetAllTheatres,
GetAllTheatresByOwner,
} from "../../apicalls/theatres";
import { useDispatch, useSelector } from "react-redux";
import { HideLoading, ShowLoading } from "../../redux/loadersSlice";
import { message, Table } from "antd";
import Shows from "./Shows";
function TheatresList() {
const { user } = useSelector((state) => state.users);
const [showTheatreFormModal = false, setShowTheatreFormModal] =
useState(false);
const [selectedTheatre = null, setSelectedTheatre] = useState(null);
const [formType = "add", setFormType] = useState("add");
const [theatres, setTheatres] = useState([]);
const [openShowsModal = false, setOpenShowsModal] = useState(false);
const dispatch = useDispatch();
const navigate = useNavigate();
const getData = async () => {
try {
dispatch(ShowLoading());
const response = await GetAllTheatresByOwner({
owner: user._id,
});
if (response.success) {
setTheatres(response.data);
} else {
message.error(response.message);
}
dispatch(HideLoading());
} catch (error) {
dispatch(HideLoading());
message.error(error.message);
}
};
const handleDelete = async (id) => {
try {
dispatch(ShowLoading());
const response = await DeleteTheatre({ theatreId: id });
if (response.success) {
message.success(response.message);
getData();
} else {
message.error(response.message);
}
dispatch(HideLoading());
} catch (error) {
dispatch(HideLoading());
message.error(error.message);
}
};
const columns = [
{
title: "Name",
dataIndex: "name",
},
{
title: "Address",
dataIndex: "address",
},
{
title: "Phone",
dataIndex: "phone",
},
{
title: "Email",
dataIndex: "email",
},
{
title: "Status",
dataIndex: "isActive",
render: (text, record) => {
if (text) {
return "Approved";
} else {
return "Pending / Blocked";
}
},
},
{
title: "Action",
dataIndex: "action",
render: (text, record) => {
return (
<div className = "flex gap-1 items-center">
<i
className = "ri-delete-bin-line"
onClick = {() => {
handleDelete(record._id);
}}
></i>
<i
className = "ri-pencil-line"
onClick = {() => {
setFormType("edit");
setSelectedTheatre(record);
setShowTheatreFormModal(true);
}}
></i>
{record.isActive && (
<span
className = "underline"
onClick = {() => {
setSelectedTheatre(record);
setOpenShowsModal(true);
}}
>
Shows
</span>
)}
</div>
);
},
},
];
useEffect(() => {
getData();
}, []);
return (
<div>
<div className = "flex justify-end mb - 1">
<Button
variant = "outlined"
title = "Add Theatre"
onClick = {() => {
setFormType("add");
setShowTheatreFormModal(true);
}}
/>
</div>
<Table columns = {columns} dataSource={theatres} />
{showTheatreFormModal && (
<TheatreForm
showTheatreFormModal = {showTheatreFormModal}
setShowTheatreFormModal = {setShowTheatreFormModal}
formType = {formType}
setFormType = {setFormType}
selectedTheatre = {selectedTheatre}
setSelectedTheatre = {setSelectedTheatre}
getData = {getData}
/>
)}
{openShowsModal && (
<Shows
openShowsModal = {openShowsModal}
setOpenShowsModal = {setOpenShowsModal}
theatre = {selectedTheatre}
/>
)}
</div>
);
}
export default TheatresList;
Certainly, here's an explanation of setSelectedTheatre
and other relevant points in the code:
-
setSelectedTheatre: This state variable is used to manage the currently selected theater. It is initially set to
null
, indicating no theater is selected. -
showTheatreFormModal: Manages the visibility of the theater form modal. It is initially set to
false
, so the modal is hidden. -
formType: Determines whether the theater form should be in "add" mode or "edit" mode. It is initially set to "add."
-
theatres: Stores an array of theater data fetched from the API.
-
openShowsModal: Controls the visibility of the modal for theater shows. It is initially set to
false
. -
handleDelete: This function handles the deletion of a theater. It sends a request to delete a theater when the delete icon is clicked.
-
columns: Defines the columns for the theater table, including actions like delete, edit, and viewing shows.
-
useEffect: Fetches theater data from the API when the component is mounted and whenever there's a change in the
theatres
state. -
Button clicks and user interactions: Various buttons and icons trigger functions like opening the theater form modal, updating theater data, deleting theaters, and viewing shows when clicked.
These elements work together to manage and display a list of theaters, allowing users to add, edit, delete, and view shows for each theater.
In the shows.js in the profile we are having:
import { Col, Form, Modal, Row, Table, message } from "antd"
import React , {useEffect, useState} from 'react'
import Button from '../../components/Button'
import {GetAllMovies} from "../../apicalls/movies"
import {AddShow, GetAllShowsByTheatre, DeleteShow} from '../../apicalls/theatres'
import moment from "moment"
import { useDispatch } from "react-redux"
import { HideLoading, ShowLoading } from "../../redux/loadersSlice"
function Shows({ openShowsModal, setOpenShowsModal, theatre }) {
let [view, setView] = useState("table");
let [movies,setMovies] = useState([]);
let [shows,setShows] = useState([]);
const dispatch = useDispatch();
const columns = [
{
title: "Show Name",
dataIndex: "name",
},
{
title: "Date",
dataIndex: "date",
render: (text, record) => {
return moment(text).format("MMM Do YYYY");
},
},
{
title: "Time",
dataIndex: "time",
},
{
title: "Movie",
dataIndex: "movie",
render: (text, record) => {
return record.movie.title;
},
},
{
title: "Ticket Price",
dataIndex: "ticketPrice",
},
{
title: "Total Seats",
dataIndex: "totalSeats",
},
{
title: "Available Seats",
dataIndex: "availableSeats",
render: (text, record) => {
return record.totalSeats - record.bookedSeats.length;
},
},
{
title: "Action",
dataIndex: "action",
render: (text, record) => {
return (
<div className = "flex gap-1 items-center">
{record.bookedSeats.length === 0 && (
<i
className = "ri-delete-bin-line"
onClick = {() => {
handleDelete(record._id);
}}
></i>
)}
</div>
);
},
},
];
useEffect(() => {
getData()
},[])
return (
<Modal title = ""
open = {openShowsModal}
onCancel = {() => setOpenShowsModal(false)}
width = {1400}
footer = {null}>
<h1 className = "text-primary text-md uppercase mb - 1">
Theatre : {theatre.name}
</h1>
<hr/>
<div className = "flex justify-between mt - 1 mb - 1 items-center">
<h1 className = "text-md uppercase">
{view === "table" ? "Shows" : "Add Show"}
</h1>
{(
<Button
variant = "outlined"
title = "Add Show"
onClick = {() => {
setView("form");
}}
/>
)}
</div>
{view === 'table' && <Table columns = {columns} dataSource = {shows}/>}
</Modal>
)
}
export default Shows
Certainly, here's an explanation of the provided React component code:
-
Component Import:
The code begins by importing necessary components and functions from various libraries, including Ant Design for UI components, Redux for state management, and custom API call functions for movies and shows. -
State Initialization:
Several state variables are initialized using theuseState
hook. These includeview
,movies
, andshows
.view
controls whether the component displays a table of shows or a form to add a new show.movies
stores a list of movies fetched from the API, andshows
stores a list of shows for the selected theatre. -
Redux Dispatch:
TheuseDispatch
hook is used to access thedispatch
function from the Redux store. This will be used to dispatch actions to update the loading state. -
Table Columns:
Thecolumns
array defines the columns for the shows table, including show name, date, time, movie, ticket price, total seats, available seats, and actions. -
Data Fetching:
TheuseEffect
hook is employed to fetch data when the component mounts. ThegetData
function is called, which fetches the shows for the selected theatre. -
Modal Component:
This component represents a modal dialog. It opens whenopenShowsModal
istrue
and displays theater-related information. -
Conditional Rendering:
The content inside the modal is conditionally rendered based on theview
state. Ifview
is "table," it displays a table of shows; if it's "form," it displays an "Add Show" form. -
Toggle View:
The "Add Show" button allows the user to toggle between the table view and the form view for adding a new show by updating theview
state. -
Rendering:
Depending on theview
, either the shows table or the "Add Show" form is displayed within the modal.
This component primarily serves as a modal for managing shows related to a theatre. It allows users to view shows in a table format and switch to a form for adding new shows.
Show Form
Now to add the functionality of the form after clicking on the add show button is explained as below:
{view === "form" && (
<Form layout = "vertical" onFinish = {handleAddShow}>
<Row gutter = {[16, 16]}>
<Col span = {8}>
<Form.Item
label = "Show Name"
name = "name"
rules = {[{ required: true, message: "Please input show name!" }]}
>
<input />
</Form.Item>
</Col>
<Col span = {8}>
<Form.Item
label = "Date"
name = "date"
rules = {[{ required: true, message: "Please input show date!" }]}
>
<input
type = "date"
min = {new Date()}
/>
</Form.Item>
</Col>
<Col span = {8}>
<Form.Item
label = "Time"
name = "time"
rules = {[{ required: true, message: "Please input show time!" }]}
>
<input type = "time" />
</Form.Item>
</Col>
<Col span = {8}>
<Form.Item
label = "Movie"
name = "movie"
rules = {[{ required: true, message: "Please select movie!" }]}
>
<select>
<option value = "">Select Movie</option>
{movies.map((movie) => (
<option value = {movie._id}>{movie.title}</option>
))}
</select>
</Form.Item>
</Col>
<Col span = {8}>
<Form.Item
label = "Ticket Price"
name = "ticketPrice"
rules = {[
{ required: true, message: "Please input ticket price!" },
]}
>
<input type = "number" />
</Form.Item>
</Col>
<Col span = {8}>
<Form.Item
label = "Total Seats"
name = "totalSeats"
rules = {[
{ required: true, message: "Please input total seats!" },
]}
>
<input type = "number" />
</Form.Item>
</Col>
</Row>
<div className = "flex justify-end gap-1">
<Button
variant = "outlined"
title = "Cancel"
onClick = {() => {
setView("table");
}}
/>
<Button variant = "contained" title = "SAVE" type = "submit" />
</div>
</Form>
)}
Certainly, here's an explanation of the provided code for rendering the "Add Show" form within a conditional block:
-
Conditional Rendering:
The code utilizes a conditional rendering approach based on theview
state. Whenview
is equal to "form," the "Add Show" form is rendered. -
Form Component:
The form is created using the<Form>
component from Ant Design. It specifies thelayout
as "vertical" to arrange form items vertically. -
Form Fields:
- Show Name:
An input field for entering the name of the show is provided. It is wrapped in a<Form.Item>
component with validation rules to ensure that the field is required. - Date:
An input field with the type "date" is used for selecting the date of the show. It includes amin
attribute to ensure that users cannot select dates in the past. - Time:
An input field with the type "time" allows users to input the time of the show. It is also wrapped in a<Form.Item>
with required validation. - Movie:
A<select>
dropdown is used for selecting the movie associated with the show. It dynamically populates the options based on the movies fetched earlier and is required. - Ticket Price:
Users can input the ticket price for the show as a number. It is validated as a required field. - Total Seats:
An input field for entering the total number of seats available for the show. It is also validated as a required field.
- Show Name:
-
Form Submission:
The form has a "SAVE" button for submitting the data. When the form is submitted, it calls thehandleAddShow
function. -
Cancel Button:
A "Cancel" button is provided to switch the view back to the table view by updating theview
state to "table."
Now lets create a showModel.js
to create the model as shown below:
const mongoose = require('mongoose');
const showSchema = new mongoose.Schema({
name:{
type:String,
required:true
},
date:{
type:Date,
required:true
},
time:{
type:String,
required:true
},
movie:{
type:mongoose.Schema.Types.ObjectId,
ref:'movies',
required:true,
},
ticketPrice:{
type:Number,
required:true
},
totalSeats:{
type:Number,
required:true
},
bookedSeats:{
type:Array,
default:[]
},
theatre:{
type:mongoose.Schema.Types.ObjectId,
ref:"theatres",
required:true
}
},{timestamps:true})
module.exports = mongoose.model('shows',showSchema);
The provided code defines a Mongoose schema for a "shows" collection in a MongoDB database. Here's a brief explanation:
- Schema Definition:
It defines a schema with various fields such as "name," "date," "time," "movie," "ticketPrice," "totalSeats," "bookedSeats," and "theatre." - Field Types:
Fields have specified data types like strings, dates, numbers, and references to other collections (e.g., "movies" and "theatres"). - Required Fields:
Certain fields like "name," "date," "time," "movie," "ticketPrice," "totalSeats," and "theatre" are marked as required. - Default Value:
The "bookedSeats" field is initialized as an empty array by default. - Timestamps:
The schema includes timestamps for when documents are created and updated. - Export:
The schema is exported as a Mongoose model for use in the application, allowing interactions with the "shows" collection in the database.
In the theater.js aslo set the api calls like as shown below:
export const AddShow = async (payload) => {
try{
const response = await axiosInstance.post('/api/theatres/add-show',payload);
return response.data;
}catch(err){
return err.response;
}
}
In the theaterRoute set the route as shown below:
//add a Show
router.post('/add-show',authMiddleware,async(req,res) => {
try{
const newShow = new Show(req.body);
await newShow.save();
res.send({
success:true,
message:"Show Added"
})
}catch(err){
res.send({
success:false,
message:err.message
})
}
})
The provided code defines an Express.js route for adding a new show to a theater. Here's a breakdown of the code:
- Route Definition:
This code defines a POST route at the endpoint '/add-show'. It is protected by the 'authMiddleware', which likely ensures that only authenticated users can access this endpoint. - Request Handling:
When a POST request is made to this endpoint, the route's callback function is executed. - Show Creation:
Inside the try block, a new instance of the 'Show' model (presumably defined elsewhere in the code) is created. It uses the request body (req.body) to populate the show's details, such as name, date, time, movie, ticket price, total seats, etc. - Saving to Database:
The new show object is then saved to the database using the 'await newShow.save()' method, which is an asynchronous operation. - Response:
If the show is successfully saved to the database, a success response is sent with a message indicating that the show has been added. If there's an error during the process (e.g., validation error or a database issue), an error response is sent with an error message.
Asking Question How we can make sure to show every movie in the dropdown in the add show form?
function Shows({ openShowsModal, setOpenShowsModal, theatre }) {
let [view, setView] = useState("table");
let [movies,setMovies] = useState([]);
let [shows,setShows] = useState([]);
const dispatch = useDispatch();
const getData = async () => {
try{
dispatch(ShowLoading());
const moviesResponse = await GetAllMovies();
if(moviesResponse.success){
setMovies(moviesResponse.data);
}else{
message.error(moviesResponse.message)
}
const showsResponse = await GetAllShowsByTheatre({theatreId:theatre._id});
if(showsResponse.success){
setShows(showsResponse.data)
}else{
message.error(showsResponse.message);
}
dispatch(HideLoading());
}catch(error){
message.error(error.message)
dispatch(HideLoading());
}
}
The provided React component, 'Shows', is responsible for managing and displaying theater shows. Here's a breakdown of the code:
-
State Management:
The component manages three pieces of state: 'view' (for toggling between table and form view), 'movies' (to store movie data), and 'shows' (to store show data). -
Dispatch and Data Retrieval:
The 'dispatch' function from Redux is initialized. When the component mounts, the 'getData' function is called asynchronously. -
Data Fetching:
Inside 'getData', the component dispatches a loading action and proceeds to fetch data. First, it fetches movies using 'GetAllMovies' and updates the 'movies' state with the response data if successful. It displays an error message if not. -
Fetching Shows by Theatre:
Next, it fetches shows specific to the provided theater ('theatreId') using 'GetAllShowsByTheatre'. The retrieved shows are stored in the 'shows' state, and any error results in an error message. -
Loading Handling:
Loading actions are dispatched and hidden during data retrieval to provide feedback to the user.
In the theaterRoute set the route to get shows based on theatres:
//get shows based on theatres
router.post('/get-all-shows-by-theatre',authMiddleware,async(req,res) => {
try{
const shows = await Show.find({theatre:req.body.theatreId}).populate('movie');
res.send({
success:true,
message:"Shows Fetched",
data:shows
})
}catch(err){
res.send({
success:false,
message:err.message
})
}
})
- The 'get-all-shows-by-theatre' route is protected by authentication middleware. It retrieves show data based on the provided theater ID ('
theatreId
'). - Using Mongoose, it fetches shows associated with the specified theater, populating the 'movie' field with movie details.
- The retrieved shows are sent as a response with success status, or an error message is provided if there's an issue with the database query.